mirror of
https://github.com/RafaelSolVargas/Vulkan.git
synced 2025-10-29 16:57:23 +00:00
Modifying play and prev commands to work with Process
This commit is contained in:
@@ -21,7 +21,7 @@ class Configs(Singleton):
|
|||||||
|
|
||||||
self.MAX_PLAYLIST_LENGTH = 50
|
self.MAX_PLAYLIST_LENGTH = 50
|
||||||
self.MAX_PLAYLIST_FORCED_LENGTH = 5
|
self.MAX_PLAYLIST_FORCED_LENGTH = 5
|
||||||
self.MAX_PRELOAD_SONGS = 10
|
self.MAX_PRELOAD_SONGS = 15
|
||||||
self.MAX_SONGS_HISTORY = 15
|
self.MAX_SONGS_HISTORY = 15
|
||||||
|
|
||||||
self.INVITE_MESSAGE = """To invite Vulkan to your own server, click [here]({}).
|
self.INVITE_MESSAGE = """To invite Vulkan to your own server, click [here]({}).
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ class ClearHandler(AbstractHandler):
|
|||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
# Get the current process of the guild
|
# Get the current process of the guild
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext:
|
if processInfo:
|
||||||
# Clear the playlist
|
# Clear the playlist
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
with processContext.getLock():
|
with processInfo.getLock():
|
||||||
playlist.clear()
|
playlist.clear()
|
||||||
|
|
||||||
return HandlerResponse(self.ctx)
|
return HandlerResponse(self.ctx)
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ class HistoryHandler(AbstractHandler):
|
|||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
# Get the current process of the guild
|
# Get the current process of the guild
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext:
|
if processInfo:
|
||||||
with processContext.getLock():
|
with processInfo.getLock():
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
history = playlist.getSongsHistory()
|
history = playlist.getSongsHistory()
|
||||||
else:
|
else:
|
||||||
history = []
|
history = []
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ class LoopHandler(AbstractHandler):
|
|||||||
async def run(self, args: str) -> HandlerResponse:
|
async def run(self, args: str) -> HandlerResponse:
|
||||||
# Get the current process of the guild
|
# Get the current process of the guild
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if not processContext:
|
if not processInfo:
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
|
|
||||||
with processContext.getLock():
|
with processInfo.getLock():
|
||||||
if args == '' or args is None:
|
if args == '' or args is None:
|
||||||
playlist.loop_all()
|
playlist.loop_all()
|
||||||
embed = self.embeds.LOOP_ALL_ACTIVATED()
|
embed = self.embeds.LOOP_ALL_ACTIVATED()
|
||||||
|
|||||||
@@ -14,19 +14,19 @@ class MoveHandler(AbstractHandler):
|
|||||||
|
|
||||||
async def run(self, pos1: str, pos2: str) -> HandlerResponse:
|
async def run(self, pos1: str, pos2: str) -> HandlerResponse:
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if not processContext:
|
if not processInfo:
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
with processContext.getLock():
|
with processInfo.getLock():
|
||||||
error = self.__validateInput(pos1, pos2)
|
error = self.__validateInput(pos1, pos2)
|
||||||
if error:
|
if error:
|
||||||
embed = self.embeds.ERROR_EMBED(error.message)
|
embed = self.embeds.ERROR_EMBED(error.message)
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
pos1, pos2 = self.__sanitizeInput(playlist, pos1, pos2)
|
pos1, pos2 = self.__sanitizeInput(playlist, pos1, pos2)
|
||||||
|
|
||||||
if not playlist.validate_position(pos1) or not playlist.validate_position(pos2):
|
if not playlist.validate_position(pos1) or not playlist.validate_position(pos2):
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ class NowPlayingHandler(AbstractHandler):
|
|||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
# Get the current process of the guild
|
# Get the current process of the guild
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if not processContext:
|
if not processInfo:
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
return HandlerResponse(self.ctx, embed)
|
return HandlerResponse(self.ctx, embed)
|
||||||
|
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
if playlist.getCurrentSong() is None:
|
if playlist.getCurrentSong() is None:
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
return HandlerResponse(self.ctx, embed)
|
return HandlerResponse(self.ctx, embed)
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ class PauseHandler(AbstractHandler):
|
|||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext:
|
if processInfo:
|
||||||
# Send Pause command to be execute by player process
|
# Send Pause command to be execute by player process
|
||||||
command = VCommands(VCommandsType.PAUSE, None)
|
command = VCommands(VCommandsType.PAUSE, None)
|
||||||
queue = processContext.getQueue()
|
queue = processInfo.getQueue()
|
||||||
queue.put(command)
|
queue.put(command)
|
||||||
|
|
||||||
return HandlerResponse(self.ctx)
|
return HandlerResponse(self.ctx)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import asyncio
|
||||||
|
from typing import List
|
||||||
from Config.Exceptions import DownloadingError, InvalidInput, VulkanError
|
from Config.Exceptions import DownloadingError, InvalidInput, VulkanError
|
||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
from discord import Client
|
from discord import Client
|
||||||
@@ -8,6 +10,7 @@ from Music.Downloader import Downloader
|
|||||||
from Music.Searcher import Searcher
|
from Music.Searcher import Searcher
|
||||||
from Music.Song import Song
|
from Music.Song import Song
|
||||||
from Parallelism.ProcessManager import ProcessManager
|
from Parallelism.ProcessManager import ProcessManager
|
||||||
|
from Parallelism.ProcessInfo import ProcessInfo
|
||||||
from Parallelism.Commands import VCommands, VCommandsType
|
from Parallelism.Commands import VCommands, VCommandsType
|
||||||
|
|
||||||
|
|
||||||
@@ -27,55 +30,56 @@ class PlayHandler(AbstractHandler):
|
|||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
musics = await self.__searcher.search(track)
|
# Search for musics and get the name of each song
|
||||||
if musics is None or len(musics) == 0:
|
musicsInfo = await self.__searcher.search(track)
|
||||||
|
if musicsInfo is None or len(musicsInfo) == 0:
|
||||||
raise InvalidInput(self.messages.INVALID_INPUT, self.messages.ERROR_TITLE)
|
raise InvalidInput(self.messages.INVALID_INPUT, self.messages.ERROR_TITLE)
|
||||||
|
|
||||||
for music in musics:
|
|
||||||
song = Song(music, self.player.playlist, requester)
|
|
||||||
self.player.playlist.add_song(song)
|
|
||||||
quant = len(musics)
|
|
||||||
|
|
||||||
songs_preload = self.player.playlist.getSongsToPreload()
|
|
||||||
await self.__down.preload(songs_preload)
|
|
||||||
|
|
||||||
if quant == 1:
|
|
||||||
pos = len(self.player.playlist)
|
|
||||||
song = self.__down.finish_one_song(song)
|
|
||||||
if song.problematic:
|
|
||||||
embed = self.embeds.SONG_PROBLEMATIC()
|
|
||||||
error = DownloadingError()
|
|
||||||
response = HandlerResponse(self.ctx, embed, error)
|
|
||||||
|
|
||||||
elif not self.player.playing:
|
|
||||||
embed = self.embeds.SONG_ADDED(song.title)
|
|
||||||
response = HandlerResponse(self.ctx, embed)
|
|
||||||
else:
|
|
||||||
embed = self.embeds.SONG_ADDED_TWO(song.info, pos)
|
|
||||||
response = HandlerResponse(self.ctx, embed)
|
|
||||||
else:
|
|
||||||
embed = self.embeds.SONGS_ADDED(quant)
|
|
||||||
response = HandlerResponse(self.ctx, embed)
|
|
||||||
|
|
||||||
# Get the process context for the current guild
|
# Get the process context for the current guild
|
||||||
manager = ProcessManager()
|
manager = ProcessManager()
|
||||||
processContext = manager.getPlayerContext(self.guild, self.ctx)
|
processInfo = manager.getPlayerContext(self.guild, self.ctx)
|
||||||
# Add the downloaded song to the process playlist
|
playlist = processInfo.getPlaylist()
|
||||||
# All access to shared memory should be protect by acquire the Lock
|
process = processInfo.getProcess()
|
||||||
with processContext.getLock():
|
if not process.is_alive(): # If process has not yet started, start
|
||||||
processContext.getPlaylist().add_song(song)
|
print('Starting process')
|
||||||
|
|
||||||
# If process already started send a command to the player process by queue
|
|
||||||
process = processContext.getProcess()
|
|
||||||
queue = processContext.getQueue()
|
|
||||||
if process.is_alive():
|
|
||||||
command = VCommands(VCommandsType.PLAY)
|
|
||||||
queue.put(command)
|
|
||||||
else:
|
|
||||||
# Start the process
|
|
||||||
process.start()
|
process.start()
|
||||||
|
|
||||||
return response
|
# Create the Songs objects
|
||||||
|
songs: List[Song] = []
|
||||||
|
for musicInfo in musicsInfo:
|
||||||
|
songs.append(Song(musicInfo, playlist, requester))
|
||||||
|
|
||||||
|
if len(songs) == 1:
|
||||||
|
# If only one music, download it directly
|
||||||
|
song = self.__down.finish_one_song(songs[0])
|
||||||
|
if song.problematic: # If error in download song return
|
||||||
|
embed = self.embeds.SONG_PROBLEMATIC()
|
||||||
|
error = DownloadingError()
|
||||||
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
|
# If not playing
|
||||||
|
if not playlist.getCurrentSong():
|
||||||
|
embed = self.embeds.SONG_ADDED(song.title)
|
||||||
|
response = HandlerResponse(self.ctx, embed)
|
||||||
|
else: # If already playing
|
||||||
|
pos = len(playlist.getSongs())
|
||||||
|
embed = self.embeds.SONG_ADDED_TWO(song.info, pos)
|
||||||
|
response = HandlerResponse(self.ctx, embed)
|
||||||
|
|
||||||
|
# Add the unique song to the playlist and send a command to player process
|
||||||
|
with processInfo.getLock():
|
||||||
|
playlist.add_song(song)
|
||||||
|
queue = processInfo.getQueue()
|
||||||
|
playCommand = VCommands(VCommandsType.PLAY, None)
|
||||||
|
queue.put(playCommand)
|
||||||
|
return response
|
||||||
|
|
||||||
|
else: # If multiple songs added
|
||||||
|
# Trigger a task to download all songs and then store them in the process playlist
|
||||||
|
asyncio.create_task(self.__downloadSongsAndStore(songs, processInfo))
|
||||||
|
|
||||||
|
embed = self.embeds.SONGS_ADDED(len(songs))
|
||||||
|
return HandlerResponse(self.ctx, embed)
|
||||||
|
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
if isinstance(err, VulkanError): # If error was already processed
|
if isinstance(err, VulkanError): # If error was already processed
|
||||||
@@ -89,6 +93,25 @@ class PlayHandler(AbstractHandler):
|
|||||||
|
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
|
async def __downloadSongsAndStore(self, songs: List[Song], processInfo: ProcessInfo) -> None:
|
||||||
|
playlist = processInfo.getPlaylist()
|
||||||
|
queue = processInfo.getQueue()
|
||||||
|
playCommand = VCommands(VCommandsType.PLAY, None)
|
||||||
|
# Trigger a task for each song to be downloaded
|
||||||
|
tasks: List[asyncio.Task] = []
|
||||||
|
for song in songs:
|
||||||
|
task = asyncio.create_task(self.__down.download_song(song))
|
||||||
|
tasks.append(task)
|
||||||
|
|
||||||
|
# In the original order, await for the task and then if successfully downloaded add in the playlist
|
||||||
|
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
|
||||||
|
with processInfo.getLock():
|
||||||
|
playlist.add_song(song)
|
||||||
|
queue.put(playCommand)
|
||||||
|
|
||||||
def __isUserConnected(self) -> bool:
|
def __isUserConnected(self) -> bool:
|
||||||
if self.ctx.author.voice:
|
if self.ctx.author.voice:
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
from discord.ext.commands import Context
|
from discord.ext.commands import Context
|
||||||
from discord import Client
|
from discord import Client
|
||||||
from Handlers.AbstractHandler import AbstractHandler
|
from Handlers.AbstractHandler import AbstractHandler
|
||||||
from Config.Exceptions import BadCommandUsage, ImpossibleMove, UnknownError
|
from Config.Exceptions import BadCommandUsage, ImpossibleMove
|
||||||
from Handlers.HandlerResponse import HandlerResponse
|
from Handlers.HandlerResponse import HandlerResponse
|
||||||
|
from Parallelism.ProcessManager import ProcessManager
|
||||||
|
from Parallelism.Commands import VCommands, VCommandsType
|
||||||
|
|
||||||
|
|
||||||
class PrevHandler(AbstractHandler):
|
class PrevHandler(AbstractHandler):
|
||||||
@@ -10,7 +12,15 @@ class PrevHandler(AbstractHandler):
|
|||||||
super().__init__(ctx, bot)
|
super().__init__(ctx, bot)
|
||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
if len(self.player.playlist.history()) == 0:
|
processManager = ProcessManager()
|
||||||
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
|
if not processInfo:
|
||||||
|
embed = self.embeds.NOT_PLAYING()
|
||||||
|
error = BadCommandUsage()
|
||||||
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
|
playlist = processInfo.getPlaylist()
|
||||||
|
if len(playlist.getHistory()) == 0:
|
||||||
error = ImpossibleMove()
|
error = ImpossibleMove()
|
||||||
embed = self.embeds.NOT_PREVIOUS_SONG()
|
embed = self.embeds.NOT_PREVIOUS_SONG()
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
@@ -20,41 +30,18 @@ class PrevHandler(AbstractHandler):
|
|||||||
embed = self.embeds.NO_CHANNEL()
|
embed = self.embeds.NO_CHANNEL()
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
if not self.__is_connected():
|
if playlist.isLoopingAll() or playlist.isLoopingOne():
|
||||||
success = await self.__connect()
|
|
||||||
if not success:
|
|
||||||
error = UnknownError()
|
|
||||||
embed = self.embeds.UNKNOWN_ERROR()
|
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
|
||||||
|
|
||||||
if self.player.playlist.isLoopingAll() or self.player.playlist.isLoopingOne():
|
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
embed = self.embeds.FAIL_DUE_TO_LOOP_ON()
|
embed = self.embeds.FAIL_DUE_TO_LOOP_ON()
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
await self.player.play_prev(self.ctx)
|
# Send a prev command, together with the user voice channel
|
||||||
|
prevCommand = VCommands(VCommandsType.PREV, self.ctx.author.voice.channel.id)
|
||||||
|
queue = processInfo.getQueue()
|
||||||
|
queue.put(prevCommand)
|
||||||
|
|
||||||
def __user_connected(self) -> bool:
|
def __user_connected(self) -> bool:
|
||||||
if self.ctx.author.voice:
|
if self.ctx.author.voice:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __is_connected(self) -> bool:
|
|
||||||
try:
|
|
||||||
voice_channel = self.guild.voice_client.channel
|
|
||||||
|
|
||||||
if not self.guild.voice_client.is_connected():
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def __connect(self) -> bool:
|
|
||||||
# if self.guild.voice_client is None:
|
|
||||||
try:
|
|
||||||
await self.ctx.author.voice.channel.connect(reconnect=True, timeout=None)
|
|
||||||
return True
|
|
||||||
except:
|
|
||||||
return False
|
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ class QueueHandler(AbstractHandler):
|
|||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
# Retrieve the process of the guild
|
# Retrieve the process of the guild
|
||||||
process = ProcessManager()
|
process = ProcessManager()
|
||||||
processContext = process.getRunningPlayerContext(self.guild)
|
processInfo = process.getRunningPlayerInfo(self.guild)
|
||||||
if not processContext: # If no process return empty list
|
if not processInfo: # If no process return empty list
|
||||||
embed = self.embeds.EMPTY_QUEUE()
|
embed = self.embeds.EMPTY_QUEUE()
|
||||||
return HandlerResponse(self.ctx, embed)
|
return HandlerResponse(self.ctx, embed)
|
||||||
|
|
||||||
# Acquire the Lock to manipulate the playlist
|
# Acquire the Lock to manipulate the playlist
|
||||||
with processContext.getLock():
|
with processInfo.getLock():
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
|
|
||||||
if playlist.isLoopingOne():
|
if playlist.isLoopingOne():
|
||||||
song = playlist.getCurrentSong()
|
song = playlist.getCurrentSong()
|
||||||
@@ -31,6 +31,7 @@ class QueueHandler(AbstractHandler):
|
|||||||
return HandlerResponse(self.ctx, embed)
|
return HandlerResponse(self.ctx, embed)
|
||||||
|
|
||||||
songs_preload = playlist.getSongsToPreload()
|
songs_preload = playlist.getSongsToPreload()
|
||||||
|
allSongs = playlist.getSongs()
|
||||||
if len(songs_preload) == 0:
|
if len(songs_preload) == 0:
|
||||||
embed = self.embeds.EMPTY_QUEUE()
|
embed = self.embeds.EMPTY_QUEUE()
|
||||||
return HandlerResponse(self.ctx, embed)
|
return HandlerResponse(self.ctx, embed)
|
||||||
@@ -43,7 +44,7 @@ class QueueHandler(AbstractHandler):
|
|||||||
title = self.messages.QUEUE_TITLE
|
title = self.messages.QUEUE_TITLE
|
||||||
|
|
||||||
total_time = Utils.format_time(sum([int(song.duration if song.duration else 0)
|
total_time = Utils.format_time(sum([int(song.duration if song.duration else 0)
|
||||||
for song in songs_preload]))
|
for song in allSongs]))
|
||||||
total_songs = len(playlist.getSongs())
|
total_songs = len(playlist.getSongs())
|
||||||
|
|
||||||
text = f'📜 Queue length: {total_songs} | ⌛ Duration: `{total_time}` downloaded \n\n'
|
text = f'📜 Queue length: {total_songs} | ⌛ Duration: `{total_time}` downloaded \n\n'
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ class RemoveHandler(AbstractHandler):
|
|||||||
async def run(self, position: str) -> HandlerResponse:
|
async def run(self, position: str) -> HandlerResponse:
|
||||||
# Get the current process of the guild
|
# Get the current process of the guild
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if not processContext:
|
if not processInfo:
|
||||||
# Clear the playlist
|
# Clear the playlist
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
return HandlerResponse(self.ctx, embed, error)
|
return HandlerResponse(self.ctx, embed, error)
|
||||||
|
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
if playlist.getCurrentSong() is None:
|
if playlist.getCurrentSong() is None:
|
||||||
embed = self.embeds.NOT_PLAYING()
|
embed = self.embeds.NOT_PLAYING()
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
@@ -60,5 +60,5 @@ class RemoveHandler(AbstractHandler):
|
|||||||
position = int(position)
|
position = int(position)
|
||||||
|
|
||||||
if position == -1:
|
if position == -1:
|
||||||
position = len(playlist)
|
position = len(playlist.getSongs())
|
||||||
return position
|
return position
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ class ResetHandler(AbstractHandler):
|
|||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
# Get the current process of the guild
|
# Get the current process of the guild
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext:
|
if processInfo:
|
||||||
command = VCommands(VCommandsType.RESET, None)
|
command = VCommands(VCommandsType.RESET, None)
|
||||||
queue = processContext.getQueue()
|
queue = processInfo.getQueue()
|
||||||
queue.put(command)
|
queue.put(command)
|
||||||
|
|
||||||
return HandlerResponse(self.ctx)
|
return HandlerResponse(self.ctx)
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ class ResumeHandler(AbstractHandler):
|
|||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext:
|
if processInfo:
|
||||||
# Send Resume command to be execute by player process
|
# Send Resume command to be execute by player process
|
||||||
command = VCommands(VCommandsType.RESUME, None)
|
command = VCommands(VCommandsType.RESUME, None)
|
||||||
queue = processContext.getQueue()
|
queue = processInfo.getQueue()
|
||||||
queue.put(command)
|
queue.put(command)
|
||||||
|
|
||||||
return HandlerResponse(self.ctx)
|
return HandlerResponse(self.ctx)
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ class ShuffleHandler(AbstractHandler):
|
|||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext:
|
if processInfo:
|
||||||
try:
|
try:
|
||||||
with processContext.getLock():
|
with processInfo.getLock():
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
playlist.shuffle()
|
playlist.shuffle()
|
||||||
|
|
||||||
embed = self.embeds.SONGS_SHUFFLED()
|
embed = self.embeds.SONGS_SHUFFLED()
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ class SkipHandler(AbstractHandler):
|
|||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext: # Verify if there is a running process
|
if processInfo: # Verify if there is a running process
|
||||||
playlist = processContext.getPlaylist()
|
playlist = processInfo.getPlaylist()
|
||||||
if playlist.isLoopingOne():
|
if playlist.isLoopingOne():
|
||||||
embed = self.embeds.ERROR_DUE_LOOP_ONE_ON()
|
embed = self.embeds.ERROR_DUE_LOOP_ONE_ON()
|
||||||
error = BadCommandUsage()
|
error = BadCommandUsage()
|
||||||
@@ -23,6 +23,6 @@ class SkipHandler(AbstractHandler):
|
|||||||
|
|
||||||
# Send a command to the player process to skip the music
|
# Send a command to the player process to skip the music
|
||||||
command = VCommands(VCommandsType.SKIP, None)
|
command = VCommands(VCommandsType.SKIP, None)
|
||||||
queue = processContext.getQueue()
|
queue = processInfo.getQueue()
|
||||||
queue.put(command)
|
queue.put(command)
|
||||||
return HandlerResponse(self.ctx)
|
return HandlerResponse(self.ctx)
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ class StopHandler(AbstractHandler):
|
|||||||
|
|
||||||
async def run(self) -> HandlerResponse:
|
async def run(self) -> HandlerResponse:
|
||||||
processManager = ProcessManager()
|
processManager = ProcessManager()
|
||||||
processContext = processManager.getRunningPlayerContext(self.guild)
|
processInfo = processManager.getRunningPlayerInfo(self.guild)
|
||||||
if processContext:
|
if processInfo:
|
||||||
# Send command to player process stop
|
# Send command to player process stop
|
||||||
command = VCommands(VCommandsType.STOP, None)
|
command = VCommands(VCommandsType.STOP, None)
|
||||||
queue = processContext.getQueue()
|
queue = processInfo.getQueue()
|
||||||
queue.put(command)
|
queue.put(command)
|
||||||
|
|
||||||
return HandlerResponse(self.ctx)
|
return HandlerResponse(self.ctx)
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class Playlist:
|
|||||||
|
|
||||||
return song
|
return song
|
||||||
|
|
||||||
def history(self) -> list:
|
def getHistory(self) -> list:
|
||||||
titles = []
|
titles = []
|
||||||
for song in self.__songs_history:
|
for song in self.__songs_history:
|
||||||
title = song.title if song.title else 'Unknown'
|
title = song.title if song.title else 'Unknown'
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from typing import Tuple
|
|||||||
|
|
||||||
|
|
||||||
class VCommandsType(Enum):
|
class VCommandsType(Enum):
|
||||||
PLAY_PREV = 'Play Prev'
|
PREV = 'Prev'
|
||||||
SKIP = 'Skip'
|
SKIP = 'Skip'
|
||||||
PAUSE = 'Pause'
|
PAUSE = 'Pause'
|
||||||
RESUME = 'Resume'
|
RESUME = 'Resume'
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from multiprocessing import Process, Queue
|
|||||||
from threading import Lock, Thread
|
from threading import Lock, Thread
|
||||||
from typing import Callable, List
|
from typing import Callable, List
|
||||||
from discord import Client, Guild, FFmpegPCMAudio, VoiceChannel, TextChannel
|
from discord import Client, Guild, FFmpegPCMAudio, VoiceChannel, TextChannel
|
||||||
from discord.ext.commands import Context
|
|
||||||
from Music.Playlist import Playlist
|
from Music.Playlist import Playlist
|
||||||
from Music.Song import Song
|
from Music.Song import Song
|
||||||
from Config.Configs import Configs
|
from Config.Configs import Configs
|
||||||
@@ -30,12 +29,12 @@ class TimeoutClock:
|
|||||||
class PlayerProcess(Process):
|
class PlayerProcess(Process):
|
||||||
"""Process that will play songs, receive commands from the main process by a Queue"""
|
"""Process that will play songs, receive commands from the main process by a Queue"""
|
||||||
|
|
||||||
def __init__(self, playlist: Playlist, lock: Lock, queue: Queue, guildID: int, textID: int, voiceID: int, authorID: int) -> None:
|
def __init__(self, name: str, playlist: Playlist, lock: Lock, queue: Queue, guildID: int, textID: int, voiceID: int, authorID: int) -> None:
|
||||||
"""
|
"""
|
||||||
Start a new process that will have his own bot instance
|
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
|
Due to pickle serialization, no objects are stored, the values initialization are being made in the run method
|
||||||
"""
|
"""
|
||||||
Process.__init__(self, group=None, target=None, args=(), kwargs={})
|
Process.__init__(self, name=name, group=None, target=None, args=(), kwargs={})
|
||||||
# Synchronization objects
|
# Synchronization objects
|
||||||
self.__playlist: Playlist = playlist
|
self.__playlist: Playlist = playlist
|
||||||
self.__lock: Lock = lock
|
self.__lock: Lock = lock
|
||||||
@@ -64,6 +63,7 @@ class PlayerProcess(Process):
|
|||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
"""Method called by process.start(), this will exec the actually _run method in a event loop"""
|
"""Method called by process.start(), this will exec the actually _run method in a event loop"""
|
||||||
try:
|
try:
|
||||||
|
print(f'Starting Process {self.name}')
|
||||||
self.__loop = asyncio.get_event_loop()
|
self.__loop = asyncio.get_event_loop()
|
||||||
self.__configs = Configs()
|
self.__configs = Configs()
|
||||||
|
|
||||||
@@ -99,16 +99,17 @@ class PlayerProcess(Process):
|
|||||||
self.__timer.cancel()
|
self.__timer.cancel()
|
||||||
|
|
||||||
async def __playPlaylistSongs(self) -> None:
|
async def __playPlaylistSongs(self) -> None:
|
||||||
print(f'Playing: {self.__playing}')
|
|
||||||
if not self.__playing:
|
if not self.__playing:
|
||||||
with self.__lock:
|
with self.__lock:
|
||||||
print('Next Song Aqui')
|
|
||||||
song = self.__playlist.next_song()
|
song = self.__playlist.next_song()
|
||||||
|
|
||||||
await self.__playSong(song)
|
await self.__playSong(song)
|
||||||
|
|
||||||
async def __playSong(self, song: Song) -> None:
|
async def __playSong(self, song: Song) -> None:
|
||||||
try:
|
try:
|
||||||
|
if song is None:
|
||||||
|
return
|
||||||
|
|
||||||
if song.source is None:
|
if song.source is None:
|
||||||
return self.__playNext(None)
|
return self.__playNext(None)
|
||||||
|
|
||||||
@@ -140,19 +141,38 @@ class PlayerProcess(Process):
|
|||||||
else:
|
else:
|
||||||
self.__playing = False
|
self.__playing = False
|
||||||
|
|
||||||
|
async def __playPrev(self, voiceChannelID: int) -> None:
|
||||||
|
with self.__lock:
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
|
||||||
|
await self.__playSong(song)
|
||||||
|
|
||||||
def __commandsReceiver(self) -> None:
|
def __commandsReceiver(self) -> None:
|
||||||
while True:
|
while True:
|
||||||
command: VCommands = self.__queue.get()
|
command: VCommands = self.__queue.get()
|
||||||
type = command.getType()
|
type = command.getType()
|
||||||
args = command.getArgs()
|
args = command.getArgs()
|
||||||
|
|
||||||
print(f'Command Received: {type}')
|
print(f'Process {self.name} receive Command: {type} with Args: {args}')
|
||||||
if type == VCommandsType.PAUSE:
|
if type == VCommandsType.PAUSE:
|
||||||
self.__pause()
|
self.__pause()
|
||||||
elif type == VCommandsType.PLAY:
|
elif type == VCommandsType.PLAY:
|
||||||
self.__loop.create_task(self.__playPlaylistSongs())
|
self.__loop.create_task(self.__playPlaylistSongs())
|
||||||
elif type == VCommandsType.PLAY_PREV:
|
elif type == VCommandsType.PREV:
|
||||||
self.__playPrev()
|
self.__loop.create_task(self.__playPrev(args))
|
||||||
elif type == VCommandsType.RESUME:
|
elif type == VCommandsType.RESUME:
|
||||||
self.__resume()
|
self.__resume()
|
||||||
elif type == VCommandsType.SKIP:
|
elif type == VCommandsType.SKIP:
|
||||||
@@ -199,18 +219,6 @@ class PlayerProcess(Process):
|
|||||||
if self.__guild.voice_client is not None:
|
if self.__guild.voice_client is not None:
|
||||||
self.__guild.voice_client.stop()
|
self.__guild.voice_client.stop()
|
||||||
|
|
||||||
async def __playPrev(self, ctx: Context) -> None:
|
|
||||||
with self.__lock:
|
|
||||||
song = self.__playlist.prev_song()
|
|
||||||
if song is not None:
|
|
||||||
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
|
|
||||||
|
|
||||||
await self.__playSong(ctx, song)
|
|
||||||
|
|
||||||
async def __forceStop(self) -> None:
|
async def __forceStop(self) -> None:
|
||||||
try:
|
try:
|
||||||
if self.__guild.voice_client is None:
|
if self.__guild.voice_client is None:
|
||||||
@@ -246,7 +254,7 @@ class PlayerProcess(Process):
|
|||||||
await task
|
await task
|
||||||
self.__loop.create_task(bot.connect(reconnect=True))
|
self.__loop.create_task(bot.connect(reconnect=True))
|
||||||
# Sleep to wait connection to be established
|
# Sleep to wait connection to be established
|
||||||
await asyncio.sleep(2)
|
await self.__ensureDiscordConnection(bot)
|
||||||
|
|
||||||
return bot
|
return bot
|
||||||
|
|
||||||
@@ -279,11 +287,19 @@ class PlayerProcess(Process):
|
|||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def __ensureDiscordConnection(self, bot: Client) -> None:
|
||||||
|
"""Await in this point until connection to discord is established"""
|
||||||
|
guild = None
|
||||||
|
while guild is None:
|
||||||
|
guild = bot.get_guild(self.__guildID)
|
||||||
|
await asyncio.sleep(0.2)
|
||||||
|
|
||||||
async def __connectToVoiceChannel(self) -> bool:
|
async def __connectToVoiceChannel(self) -> bool:
|
||||||
try:
|
try:
|
||||||
await self.__voiceChannel.connect(reconnect=True, timeout=None)
|
await self.__voiceChannel.connect(reconnect=True, timeout=None)
|
||||||
return True
|
return True
|
||||||
except:
|
except Exception as e:
|
||||||
|
print(f'[ERROR CONNECTING TO VC] -> {e}')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __getBotMember(self) -> Member:
|
def __getBotMember(self) -> Member:
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class ProcessManager(Singleton):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'[Error In GetPlayerContext] -> {e}')
|
print(f'[Error In GetPlayerContext] -> {e}')
|
||||||
|
|
||||||
def getRunningPlayerContext(self, guild: Guild) -> ProcessInfo:
|
def getRunningPlayerInfo(self, guild: Guild) -> ProcessInfo:
|
||||||
"""Return the process info for the guild, if not, return None"""
|
"""Return the process info for the guild, if not, return None"""
|
||||||
if guild not in self.__playersProcess.keys():
|
if guild not in self.__playersProcess.keys():
|
||||||
return None
|
return None
|
||||||
@@ -54,10 +54,11 @@ class ProcessManager(Singleton):
|
|||||||
playlist: Playlist = self.__manager.Playlist()
|
playlist: Playlist = self.__manager.Playlist()
|
||||||
lock = Lock()
|
lock = Lock()
|
||||||
queue = Queue()
|
queue = Queue()
|
||||||
process = PlayerProcess(playlist, lock, queue, guildID, textID, voiceID, authorID)
|
process = PlayerProcess(context.guild.name, playlist, lock, queue,
|
||||||
processContext = ProcessInfo(process, queue, playlist, lock)
|
guildID, textID, voiceID, authorID)
|
||||||
|
processInfo = ProcessInfo(process, queue, playlist, lock)
|
||||||
|
|
||||||
return processContext
|
return processInfo
|
||||||
|
|
||||||
|
|
||||||
class VManager(BaseManager):
|
class VManager(BaseManager):
|
||||||
|
|||||||
Reference in New Issue
Block a user