Sending more code

This commit is contained in:
Rafael Vargas 2023-02-19 13:40:37 -03:00
parent 7d53840f87
commit 1f45b64a62
14 changed files with 69 additions and 49 deletions

View File

@ -40,7 +40,7 @@ class MusicCog(Cog):
self.__bot: VulkanBot = bot self.__bot: VulkanBot = bot
self.__embeds = VEmbeds() self.__embeds = VEmbeds()
configs = VConfigs() configs = VConfigs()
if configs.SHOULD_AUTO_DISCONNECT_WHEN_ALONE: if configs.SONG_PLAYBACK_IN_SEPARATE_PROCESS:
configs.setPlayersManager(ProcessPlayerManager(bot)) configs.setPlayersManager(ProcessPlayerManager(bot))
else: else:
configs.setPlayersManager(ThreadPlayerManager(bot)) configs.setPlayersManager(ThreadPlayerManager(bot))

View File

@ -49,7 +49,7 @@ class JumpMusicHandler(AbstractHandler):
# Send a command to the player to skip the music # Send a command to the player to skip the music
command = VCommands(VCommandsType.SKIP, None) command = VCommands(VCommandsType.SKIP, None)
playersManager.sendCommandToPlayer(command, self.guild) await playersManager.sendCommandToPlayer(command, self.guild)
return HandlerResponse(self.ctx) return HandlerResponse(self.ctx)
except: except:

View File

@ -16,7 +16,7 @@ class PauseHandler(AbstractHandler):
playersManager: AbstractPlayersManager = self.config.getPlayersManager() playersManager: AbstractPlayersManager = self.config.getPlayersManager()
if playersManager.verifyIfPlayerExists(self.guild): if playersManager.verifyIfPlayerExists(self.guild):
command = VCommands(VCommandsType.PAUSE, None) command = VCommands(VCommandsType.PAUSE, None)
playersManager.sendCommandToPlayer(command, self.guild) await playersManager.sendCommandToPlayer(command, self.guild)
embed = self.embeds.PLAYER_PAUSED() embed = self.embeds.PLAYER_PAUSED()
return HandlerResponse(self.ctx, embed) return HandlerResponse(self.ctx, embed)

View File

@ -71,7 +71,7 @@ class PlayHandler(AbstractHandler):
# Release the acquired Lock # Release the acquired Lock
playerLock.release() playerLock.release()
playCommand = VCommands(VCommandsType.PLAY, None) playCommand = VCommands(VCommandsType.PLAY, None)
playersManager.sendCommandToPlayer(playCommand, self.guild) await playersManager.sendCommandToPlayer(playCommand, self.guild)
else: else:
playersManager.resetPlayer(self.guild, self.ctx) playersManager.resetPlayer(self.guild, self.ctx)
embed = self.embeds.PLAYER_RESTARTED() embed = self.embeds.PLAYER_RESTARTED()
@ -127,7 +127,7 @@ class PlayHandler(AbstractHandler):
acquired = playerLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT) acquired = playerLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT)
if acquired: if acquired:
playlist.add_song(song) playlist.add_song(song)
playersManager.sendCommandToPlayer(playCommand, self.guild) await playersManager.sendCommandToPlayer(playCommand, self.guild)
playerLock.release() playerLock.release()
else: else:
playersManager.resetPlayer(self.guild, self.ctx) playersManager.resetPlayer(self.guild, self.ctx)

View File

@ -38,7 +38,7 @@ class PrevHandler(AbstractHandler):
# Send a prev command, together with the user voice channel # Send a prev command, together with the user voice channel
prevCommand = VCommands(VCommandsType.PREV, self.author.voice.channel.id) prevCommand = VCommands(VCommandsType.PREV, self.author.voice.channel.id)
playersManager.sendCommandToPlayer(prevCommand, self.guild) await playersManager.sendCommandToPlayer(prevCommand, self.guild)
embed = self.embeds.RETURNING_SONG() embed = self.embeds.RETURNING_SONG()
return HandlerResponse(self.ctx, embed) return HandlerResponse(self.ctx, embed)

View File

@ -16,7 +16,7 @@ class ResetHandler(AbstractHandler):
playersManager: AbstractPlayersManager = self.config.getPlayersManager() playersManager: AbstractPlayersManager = self.config.getPlayersManager()
if playersManager.verifyIfPlayerExists(self.guild): if playersManager.verifyIfPlayerExists(self.guild):
command = VCommands(VCommandsType.RESET, None) command = VCommands(VCommandsType.RESET, None)
playersManager.sendCommandToPlayer(command, self.guild) await playersManager.sendCommandToPlayer(command, self.guild)
return HandlerResponse(self.ctx) return HandlerResponse(self.ctx)
else: else:
embed = self.embeds.NOT_PLAYING() embed = self.embeds.NOT_PLAYING()

View File

@ -16,7 +16,7 @@ class ResumeHandler(AbstractHandler):
playersManager: AbstractPlayersManager = self.config.getPlayersManager() playersManager: AbstractPlayersManager = self.config.getPlayersManager()
if playersManager.verifyIfPlayerExists(self.guild): if playersManager.verifyIfPlayerExists(self.guild):
command = VCommands(VCommandsType.RESUME, None) command = VCommands(VCommandsType.RESUME, None)
playersManager.sendCommandToPlayer(command, self.guild) await playersManager.sendCommandToPlayer(command, self.guild)
embed = self.embeds.PLAYER_RESUMED() embed = self.embeds.PLAYER_RESUMED()
return HandlerResponse(self.ctx, embed) return HandlerResponse(self.ctx, embed)
else: else:

View File

@ -16,7 +16,7 @@ class SkipHandler(AbstractHandler):
playersManager: AbstractPlayersManager = self.config.getPlayersManager() playersManager: AbstractPlayersManager = self.config.getPlayersManager()
if playersManager.verifyIfPlayerExists(self.guild): if playersManager.verifyIfPlayerExists(self.guild):
command = VCommands(VCommandsType.SKIP, None) command = VCommands(VCommandsType.SKIP, None)
playersManager.sendCommandToPlayer(command, self.guild) await playersManager.sendCommandToPlayer(command, self.guild)
embed = self.embeds.SKIPPING_SONG() embed = self.embeds.SKIPPING_SONG()
return HandlerResponse(self.ctx, embed) return HandlerResponse(self.ctx, embed)
else: else:

View File

@ -16,7 +16,7 @@ class StopHandler(AbstractHandler):
playersManager: AbstractPlayersManager = self.config.getPlayersManager() playersManager: AbstractPlayersManager = self.config.getPlayersManager()
if playersManager.verifyIfPlayerExists(self.guild): if playersManager.verifyIfPlayerExists(self.guild):
command = VCommands(VCommandsType.STOP, None) command = VCommands(VCommandsType.STOP, None)
playersManager.sendCommandToPlayer(command, self.guild) await playersManager.sendCommandToPlayer(command, self.guild)
embed = self.embeds.STOPPING_PLAYER() embed = self.embeds.STOPPING_PLAYER()
return HandlerResponse(self.ctx, embed) return HandlerResponse(self.ctx, embed)
else: else:

View File

@ -13,7 +13,7 @@ class AbstractPlayersManager(ABC):
pass pass
@abstractmethod @abstractmethod
def sendCommandToPlayer(self, command: VCommands, guild: Guild, forceCreation: bool = False, context: Union[Context, Interaction] = None): async def sendCommandToPlayer(self, command: VCommands, guild: Guild, forceCreation: bool = False, context: Union[Context, Interaction] = None):
"""If the forceCreation boolean is True, then the context must be provided for the Player to be created""" """If the forceCreation boolean is True, then the context must be provided for the Player to be created"""
pass pass

View File

@ -2,11 +2,11 @@ import asyncio
from time import sleep, time from time import sleep, time
from urllib.parse import parse_qs, urlparse from urllib.parse import parse_qs, urlparse
from Music.VulkanInitializer import VulkanInitializer from Music.VulkanInitializer import VulkanInitializer
from discord import Member, VoiceClient from discord import VoiceClient
from asyncio import AbstractEventLoop, Semaphore, Queue from asyncio import AbstractEventLoop, Semaphore, Queue
from multiprocessing import Process, RLock, Lock, Queue from multiprocessing import Process, RLock, Lock, Queue
from threading import Thread from threading import Thread
from typing import Callable, List from typing import Callable
from discord import Guild, FFmpegPCMAudio, VoiceChannel from discord import Guild, FFmpegPCMAudio, VoiceChannel
from Music.Playlist import Playlist from Music.Playlist import Playlist
from Music.Song import Song from Music.Song import Song
@ -29,7 +29,7 @@ class TimeoutClock:
self.__task.cancel() self.__task.cancel()
class PlayerProcess(Process): class ProcessPlayer(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, name: str, playlist: Playlist, lock: Lock, queueToReceive: Queue, queueToSend: Queue, guildID: int, voiceID: int) -> None: def __init__(self, name: str, playlist: Playlist, lock: Lock, queueToReceive: Queue, queueToSend: Queue, guildID: int, voiceID: int) -> None:
@ -421,9 +421,3 @@ class PlayerProcess(Process):
except Exception as e: except Exception as e:
print(f'[ERROR CONNECTING TO VC] -> {e}') print(f'[ERROR CONNECTING TO VC] -> {e}')
return False return False
def __getBotMember(self) -> Member:
guild_members: List[Member] = self.__guild.members
for member in guild_members:
if member.id == self.__bot.user.id:
return member

View File

@ -6,12 +6,12 @@ from queue import Empty
from threading import Thread from threading import Thread
from typing import Dict, Tuple, Union from typing import Dict, Tuple, Union
from Config.Singleton import Singleton from Config.Singleton import Singleton
from discord import Guild, Interaction, TextChannel from discord import Guild, Interaction, TextChannel, VoiceChannel
from discord.ext.commands import Context from discord.ext.commands import Context
from Parallelism.AbstractProcessManager import AbstractPlayersManager from Parallelism.AbstractProcessManager import AbstractPlayersManager
from Parallelism.ProcessExecutor import ProcessCommandsExecutor from Parallelism.ProcessExecutor import ProcessCommandsExecutor
from Music.Song import Song from Music.Song import Song
from Parallelism.PlayerProcess import PlayerProcess from Parallelism.ProcessPlayer import ProcessPlayer
from Music.Playlist import Playlist from Music.Playlist import Playlist
from Parallelism.Commands import VCommands, VCommandsType from Parallelism.Commands import VCommands, VCommandsType
from Music.VulkanBot import VulkanBot from Music.VulkanBot import VulkanBot
@ -74,18 +74,18 @@ class ProcessPlayerManager(Singleton, AbstractPlayersManager):
if not super().created: if not super().created:
self.__bot = bot self.__bot = bot
VManager.register('Playlist', Playlist) VManager.register('Playlist', Playlist)
VManager.register('VoiceChannel', VoiceChannel)
self.__manager = VManager() self.__manager = VManager()
self.__manager.start() self.__manager.start()
self.__playersProcess: Dict[int, PlayerProcessInfo] = {} self.__playersProcess: Dict[int, PlayerProcessInfo] = {}
self.__playersListeners: Dict[int, Tuple[Thread, bool]] = {} self.__playersListeners: Dict[int, Tuple[Thread, bool]] = {}
self.__playersCommandsExecutor: Dict[int, ProcessCommandsExecutor] = {} self.__playersCommandsExecutor: Dict[int, ProcessCommandsExecutor] = {}
def sendCommandToPlayer(self, command: VCommands, guild: Guild, forceCreation: bool = False, context: Union[Context, Interaction] = None): async def sendCommandToPlayer(self, command: VCommands, guild: Guild, forceCreation: bool = False, context: Union[Context, Interaction] = None):
if forceCreation: if forceCreation:
processInfo = self.createPlayerForGuild(guild, context) processInfo = self.createPlayerForGuild(guild, context)
else: else:
processInfo = self.__getRunningPlayerInfo(guild) processInfo = self.__getRunningPlayerInfo(guild)
if processInfo == None: if processInfo == None:
return return
@ -149,7 +149,7 @@ class ProcessPlayerManager(Singleton, AbstractPlayersManager):
lock = Lock() lock = Lock()
queueToListen = Queue() queueToListen = Queue()
queueToSend = Queue() queueToSend = Queue()
process = PlayerProcess(context.guild.name, playlist, lock, queueToSend, process = ProcessPlayer(context.guild.name, playlist, lock, queueToSend,
queueToListen, guildID, voiceID) queueToListen, guildID, voiceID)
processInfo = PlayerProcessInfo(process, queueToSend, queueToListen, processInfo = PlayerProcessInfo(process, queueToSend, queueToListen,
playlist, lock, context.channel) playlist, lock, context.channel)
@ -196,7 +196,7 @@ class ProcessPlayerManager(Singleton, AbstractPlayersManager):
lock = Lock() lock = Lock()
queueToListen = Queue() queueToListen = Queue()
queueToSend = Queue() queueToSend = Queue()
process = PlayerProcess(context.guild.name, playlist, lock, queueToSend, process = ProcessPlayer(context.guild.name, playlist, lock, queueToSend,
queueToListen, guildID, textID, voiceID, authorID) queueToListen, guildID, textID, voiceID, authorID)
processInfo = PlayerProcessInfo(process, queueToSend, queueToListen, processInfo = PlayerProcessInfo(process, queueToSend, queueToListen,
playlist, lock, context.channel) playlist, lock, context.channel)

View File

@ -5,7 +5,7 @@ from discord import VoiceClient
from asyncio import AbstractEventLoop from asyncio import AbstractEventLoop
from threading import RLock, Thread from threading import RLock, Thread
from multiprocessing import Lock from multiprocessing import Lock
from typing import Callable from typing import Callable, Coroutine
from discord import Guild, FFmpegPCMAudio, VoiceChannel from discord import Guild, FFmpegPCMAudio, VoiceChannel
from Music.Playlist import Playlist from Music.Playlist import Playlist
from Music.Song import Song from Music.Song import Song
@ -28,10 +28,10 @@ class TimeoutClock:
self.__task.cancel() self.__task.cancel()
class PlayerThread(Thread): class ThreadPlayer(Thread):
"""Player Thread to control the song playback in the same Process of the Main Process""" """Player Thread to control the song playback in the same Process of the Main Process"""
def __init__(self, bot: VulkanBot, guild: Guild, name: str, voiceChannel: VoiceChannel, playlist: Playlist, lock: Lock, guildID: int, voiceID: int) -> None: def __init__(self, bot: VulkanBot, guild: Guild, name: str, voiceChannel: VoiceChannel, playlist: Playlist, lock: Lock, guildID: int, voiceID: int, callbackToSendCommand: Callable, exitCB: Callable) -> None:
Thread.__init__(self, name=name, group=None, target=None, args=(), kwargs={}) Thread.__init__(self, name=name, group=None, target=None, args=(), kwargs={})
# Synchronization objects # Synchronization objects
self.__playlist: Playlist = playlist self.__playlist: Playlist = playlist
@ -39,14 +39,15 @@ class PlayerThread(Thread):
self.__loop: AbstractEventLoop = None self.__loop: AbstractEventLoop = None
self.__playerLock: RLock = RLock() self.__playerLock: RLock = RLock()
# Discord context ID # Discord context ID
self.__guildID = guildID
self.__voiceChannelID = voiceID self.__voiceChannelID = voiceID
self.__guild: Guild = guild self.__guild: Guild = guild
self.__bot: VulkanBot = bot
self.__voiceChannel: VoiceChannel = voiceChannel self.__voiceChannel: VoiceChannel = voiceChannel
self.__voiceClient: VoiceClient = None self.__voiceClient: VoiceClient = None
self.__downloader = Downloader() self.__downloader = Downloader()
self.__callback = callbackToSendCommand
self.__exitCB = exitCB
self.__bot = bot
self.__playing = False self.__playing = False
self.__forceStop = False self.__forceStop = False
@ -57,8 +58,7 @@ class PlayerThread(Thread):
"""This method is called automatically when the Thread starts""" """This method is called automatically when the Thread starts"""
try: try:
print(f'Starting Player Thread for Guild {self.name}') print(f'Starting Player Thread for Guild {self.name}')
self.__loop = asyncio.get_event_loop_policy().new_event_loop() self.__loop = self.__bot.loop
asyncio.set_event_loop(self.__loop)
self.__loop.run_until_complete(self._run()) self.__loop.run_until_complete(self._run())
except Exception as e: except Exception as e:
@ -89,6 +89,7 @@ class PlayerThread(Thread):
song = self.__playlist.next_song() song = self.__playlist.next_song()
if song is not None: if song is not None:
print('Criando song')
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}') self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
self.__playing = True self.__playing = True
@ -131,7 +132,7 @@ class PlayerThread(Thread):
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop) self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
nowPlayingCommand = VCommands(VCommandsType.NOW_PLAYING, song) nowPlayingCommand = VCommands(VCommandsType.NOW_PLAYING, song)
self.__queueSend.put(nowPlayingCommand) await self.__callback(nowPlayingCommand, self.__guild.id, song)
except Exception as e: except Exception as e:
print(f'[ERROR IN PLAY SONG FUNCTION] -> {e}, {type(e)}') print(f'[ERROR IN PLAY SONG FUNCTION] -> {e}, {type(e)}')
self.__playNext(None) self.__playNext(None)
@ -155,11 +156,8 @@ class PlayerThread(Thread):
self.__playlist.loop_off() self.__playlist.loop_off()
self.__songPlaying = None self.__songPlaying = None
self.__playing = False self.__playing = False
# Send a command to the main process put this one to sleep # Send a command to the main process to kill this thread
sleepCommand = VCommands(VCommandsType.SLEEPING) self.__exitCB(self.__guild.id)
self.__queueSend.put(sleepCommand)
# Release the semaphore to finish the process
self.__semStopPlaying.release()
def __verifyIfSongAvailable(self, song: Song) -> bool: def __verifyIfSongAvailable(self, song: Song) -> bool:
"""Verify the song source to see if it's already expired""" """Verify the song source to see if it's already expired"""

View File

@ -1,5 +1,5 @@
from multiprocessing import Lock from multiprocessing import Lock
from typing import Dict, Union from typing import Any, Dict, Union
from Config.Singleton import Singleton from Config.Singleton import Singleton
from discord import Guild, Interaction, TextChannel from discord import Guild, Interaction, TextChannel
from discord.ext.commands import Context from discord.ext.commands import Context
@ -8,7 +8,7 @@ from Music.Song import Song
from Music.Playlist import Playlist from Music.Playlist import Playlist
from Parallelism.Commands import VCommands, VCommandsType from Parallelism.Commands import VCommands, VCommandsType
from Music.VulkanBot import VulkanBot from Music.VulkanBot import VulkanBot
from Parallelism.PlayerThread import PlayerThread from Parallelism.ThreadPlayer import ThreadPlayer
class ThreadPlayerInfo: class ThreadPlayerInfo:
@ -16,13 +16,13 @@ class ThreadPlayerInfo:
Class to store the reference to all structures to maintain a player thread Class to store the reference to all structures to maintain a player thread
""" """
def __init__(self, thread: PlayerThread, playlist: Playlist, lock: Lock, textChannel: TextChannel) -> None: def __init__(self, thread: ThreadPlayer, playlist: Playlist, lock: Lock, textChannel: TextChannel) -> None:
self.__thread = thread self.__thread = thread
self.__playlist = playlist self.__playlist = playlist
self.__lock = lock self.__lock = lock
self.__textChannel = textChannel self.__textChannel = textChannel
def getThread(self) -> PlayerThread: def getPlayer(self) -> ThreadPlayer:
return self.__thread return self.__thread
def getPlaylist(self) -> Playlist: def getPlaylist(self) -> Playlist:
@ -45,8 +45,23 @@ class ThreadPlayerManager(Singleton, AbstractPlayersManager):
self.__bot = bot self.__bot = bot
self.__playersThreads: Dict[int, ThreadPlayerInfo] = {} self.__playersThreads: Dict[int, ThreadPlayerInfo] = {}
def sendCommandToPlayer(self, command: VCommands, guild: Guild, forceCreation: bool = False, context: Union[Context, Interaction] = None): async def sendCommandToPlayer(self, command: VCommands, guild: Guild, forceCreation: bool = False, context: Union[Context, Interaction] = None):
return super().sendCommandToPlayer(command, guild, forceCreation, context) playerInfo = self.__playersThreads[guild.id]
player = playerInfo.getPlayer()
if player is None and forceCreation:
self.__createPlayerThreadInfo(context)
if player is None:
return
await player.receiveCommand(command)
async def __receiveCommand(self, command: VCommands, guildID: int, args: Any) -> None:
commandType = command.getType()
if commandType == VCommandsType.NOW_PLAYING:
await self.showNowPlaying(guildID, args)
else:
print(
f'[ERROR] -> Command not processable received from Thread {guildID}: {commandType}')
def getPlayerPlaylist(self, guild: Guild) -> Playlist: def getPlayerPlaylist(self, guild: Guild) -> Playlist:
playerInfo = self.__getRunningPlayerInfo(guild) playerInfo = self.__getRunningPlayerInfo(guild)
@ -67,7 +82,7 @@ class ThreadPlayerManager(Singleton, AbstractPlayersManager):
self.__playersThreads[guild.id] = self.__createPlayerThreadInfo(context) self.__playersThreads[guild.id] = self.__createPlayerThreadInfo(context)
else: else:
# If the thread has ended create a new one # If the thread has ended create a new one
if not self.__playersThreads[guild.id].getThread().is_alive(): if not self.__playersThreads[guild.id].getPlayer().is_alive():
self.__playersThreads[guild.id] = self.__recreateThread(guild, context) self.__playersThreads[guild.id] = self.__recreateThread(guild, context)
return self.__playersThreads[guild.id] return self.__playersThreads[guild.id]
@ -80,7 +95,7 @@ class ThreadPlayerManager(Singleton, AbstractPlayersManager):
# Recreate the thread keeping the playlist # Recreate the thread keeping the playlist
newPlayerInfo = self.__recreateThread(guild, context) newPlayerInfo = self.__recreateThread(guild, context)
newPlayerInfo.getThread().start() newPlayerInfo.getPlayer().start()
# Send a command to start the play again # Send a command to start the play again
playCommand = VCommands(VCommandsType.PLAY) playCommand = VCommands(VCommandsType.PLAY)
newPlayerInfo.getQueueToPlayer().put(playCommand) newPlayerInfo.getQueueToPlayer().put(playCommand)
@ -100,14 +115,25 @@ class ThreadPlayerManager(Singleton, AbstractPlayersManager):
else: else:
voiceID: int = context.author.voice.channel.id voiceID: int = context.author.voice.channel.id
voiceChannel = self.__bot.get_channel(voiceID)
playlist = Playlist() playlist = Playlist()
lock = Lock() lock = Lock()
player = PlayerThread(context.guild.name, playlist, lock, guildID, voiceID) player = ThreadPlayer(self.__bot, context.guild, context.guild.name,
voiceChannel, playlist, lock, guildID, voiceID, self.__receiveCommand, self.__deleteThread)
playerInfo = ThreadPlayerInfo(player, playlist, lock, context.channel) playerInfo = ThreadPlayerInfo(player, playlist, lock, context.channel)
player.start() player.start()
return playerInfo return playerInfo
def __deleteThread(self, guildID: int) -> None:
"""Tries to delete the thread and removes all the references to it"""
playerInfo = self.__playersThreads[guildID]
if playerInfo:
thread = playerInfo.getPlayer()
del thread
self.__playersThreads.popitem(thread)
def __recreateThread(self, guild: Guild, context: Union[Context, Interaction]) -> ThreadPlayerInfo: def __recreateThread(self, guild: Guild, context: Union[Context, Interaction]) -> ThreadPlayerInfo:
self.__stopPossiblyRunningProcess(guild) self.__stopPossiblyRunningProcess(guild)
@ -116,10 +142,12 @@ class ThreadPlayerManager(Singleton, AbstractPlayersManager):
voiceID: int = context.user.voice.channel.id voiceID: int = context.user.voice.channel.id
else: else:
voiceID: int = context.author.voice.channel.id voiceID: int = context.author.voice.channel.id
voiceChannel = self.__bot.get_channel(voiceID)
playlist = self.__playersThreads[guildID].getPlaylist() playlist = self.__playersThreads[guildID].getPlaylist()
lock = Lock() lock = Lock()
player = PlayerThread(context.guild.name, playlist, lock, guildID, voiceID) player = ThreadPlayer(self.__bot, context.guild, context.guild.name,
voiceChannel, playlist, lock, guildID, voiceID, self.__receiveCommand, self.__deleteThread)
playerInfo = ThreadPlayerInfo(player, playlist, lock, context.channel) playerInfo = ThreadPlayerInfo(player, playlist, lock, context.channel)
player.start() player.start()