Fixing erros due to processing

This commit is contained in:
Rafael Vargas 2022-07-24 14:25:44 -03:00
parent 56456bf2ed
commit b904c75caa
16 changed files with 179 additions and 305 deletions

View File

@ -14,8 +14,8 @@ class Messages(Singleton):
self.SONGINFO_REQUESTER = 'Requester: '
self.SONGINFO_POSITION = 'Position: '
self.SONGS_ADDED = 'You added {} songs to the queue'
self.SONG_ADDED = 'You added the song `{}` to the queue'
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'
@ -61,7 +61,7 @@ class Messages(Singleton):
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 = '❌ An error occurred while downloading'
self.DOWNLOADING_ERROR = "❌ It's impossible to download and play this video"
self.EXTRACTING_ERROR = '❌ An error ocurred while searching for the songs'
self.MY_ERROR_BAD_COMMAND = 'This string serves to verify if some error was raised by myself on purpose'

View File

@ -19,7 +19,7 @@ class ControlCog(commands.Cog):
self.__messages = Messages()
self.__colors = Colors()
self.__embeds = Embeds()
self.__comandos = {
self.__commands = {
'MUSIC': ['resume', 'pause', 'loop', 'stop',
'skip', 'play', 'queue', 'clear',
'np', 'shuffle', 'move', 'remove',
@ -80,10 +80,10 @@ class ControlCog(commands.Cog):
help_help = '👾 `HELP`\n'
for command in self.__bot.commands:
if command.name in self.__comandos['MUSIC']:
if command.name in self.__commands['MUSIC']:
help_music += f'**{command}** - {command.help}\n'
elif command.name in self.__comandos['RANDOM']:
elif command.name in self.__commands['RANDOM']:
help_random += f'**{command}** - {command.help}\n'
else:

View File

@ -6,12 +6,10 @@ from Handlers.ClearHandler import ClearHandler
from Handlers.MoveHandler import MoveHandler
from Handlers.NowPlayingHandler import NowPlayingHandler
from Handlers.PlayHandler import PlayHandler
from Handlers.PlayersController import PlayersController
from Handlers.PrevHandler import PrevHandler
from Handlers.RemoveHandler import RemoveHandler
from Handlers.ResetHandler import ResetHandler
from Handlers.ShuffleHandler import ShuffleHandler
from Utils.Cleaner import Cleaner
from Handlers.SkipHandler import SkipHandler
from Handlers.PauseHandler import PauseHandler
from Handlers.StopHandler import StopHandler
@ -34,16 +32,6 @@ class MusicCog(commands.Cog):
def __init__(self, bot) -> None:
self.__bot: Client = bot
self.__cleaner = Cleaner(self.__bot)
self.__controller = PlayersController(self.__bot)
@commands.Cog.listener()
async def on_ready(self) -> None:
self.__controller = PlayersController(self.__bot)
@commands.Cog.listener()
async def on_guild_join(self, guild: Guild) -> None:
self.__controller.create_player(guild)
@commands.command(name="play", help=helper.HELP_PLAY, description=helper.HELP_PLAY_LONG, aliases=['p', 'tocar'])
async def play(self, ctx: Context, *args) -> None:

View File

@ -3,8 +3,6 @@ from typing import List
from discord.ext.commands import Context
from discord import Client, Guild, ClientUser, Member
from Config.Messages import Messages
from Handlers.PlayersController import PlayersController
from Music.Player import Player
from Handlers.HandlerResponse import HandlerResponse
from Config.Configs import Configs
from Config.Helper import Helper
@ -14,8 +12,6 @@ from Views.Embeds import Embeds
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
self.__ctx: Context = ctx
self.__bot_user: ClientUser = self.__bot.user
@ -46,14 +42,6 @@ class AbstractHandler(ABC):
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

View File

@ -37,11 +37,10 @@ class PlayHandler(AbstractHandler):
# Get the process context for the current guild
manager = ProcessManager()
processInfo = manager.getPlayerContext(self.guild, self.ctx)
processInfo = manager.getPlayerInfo(self.guild, self.ctx)
playlist = processInfo.getPlaylist()
process = processInfo.getProcess()
if not process.is_alive(): # If process has not yet started, start
print('Starting process')
process.start()
# Create the Songs objects
@ -57,22 +56,21 @@ class PlayHandler(AbstractHandler):
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
# If not playing
if not playlist.getCurrentSong():
embed = self.embeds.SONG_ADDED(song.title)
return HandlerResponse(self.ctx, embed)
else: # If already playing
pos = len(playlist.getSongs())
embed = self.embeds.SONG_ADDED_TWO(song.info, pos)
return HandlerResponse(self.ctx, embed)
else: # If multiple songs added
# Trigger a task to download all songs and then store them in the process playlist
@ -81,13 +79,15 @@ class PlayHandler(AbstractHandler):
embed = self.embeds.SONGS_ADDED(len(songs))
return HandlerResponse(self.ctx, embed)
except Exception as err:
if isinstance(err, VulkanError): # If error was already processed
print(f'DEVELOPER NOTE -> PlayController Error: {err.message}')
error = err
except DownloadingError as error:
embed = self.embeds.DOWNLOADING_ERROR()
return HandlerResponse(self.ctx, embed, error)
except Exception as error:
if isinstance(error, VulkanError): # If error was already processed
print(f'DEVELOPER NOTE -s> PlayController Error: {error.message}', {type(error)})
embed = self.embeds.CUSTOM_ERROR(error)
else:
print(f'DEVELOPER NOTE -> PlayController Error: {err}')
print(f'DEVELOPER NOTE -> PlayController Error: {error}, {type(error)}')
error = UnknownError()
embed = self.embeds.UNKNOWN_ERROR()

View File

@ -1,56 +0,0 @@
from typing import Dict, List, Union
from Config.Singleton import Singleton
from discord import Guild, Client, VoiceClient, Member
from 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_player(self, guild: Guild) -> None:
player = Player(self.__bot, guild)
self.__players[guild] = player
print(f'Player for guild {guild.name} created')
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
print(f'Player for guild {guild.name} created')
return players
def __get_guild_bot_member(self, guild: Guild) -> Member:
members: List[Member] = guild.members
for member in members:
if member.id == self.__bot.user.id:
return member

View File

@ -13,7 +13,7 @@ class PrevHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
processManager = ProcessManager()
processInfo = processManager.getRunningPlayerInfo(self.guild)
processInfo = processManager.getPlayerInfo(self.guild, self.ctx)
if not processInfo:
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
@ -35,6 +35,11 @@ class PrevHandler(AbstractHandler):
embed = self.embeds.FAIL_DUE_TO_LOOP_ON()
return HandlerResponse(self.ctx, embed, error)
# If not started, start the player process
process = processInfo.getProcess()
if not process.is_alive():
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()

View File

@ -1,10 +1,11 @@
import asyncio
from typing import List
from Config.Configs import Configs
from yt_dlp import YoutubeDL
from yt_dlp import YoutubeDL, DownloadError
from concurrent.futures import ThreadPoolExecutor
from Music.Song import Song
from Utils.Utils import Utils, run_async
from Config.Exceptions import DownloadingError
class Downloader:
@ -40,16 +41,20 @@ class Downloader:
self.__playlist_keys = ['entries']
def finish_one_song(self, song: Song) -> Song:
if song.identifier is None:
return None
try:
if song.identifier is None:
return None
if Utils.is_url(song.identifier):
song_info = self.__download_url(song.identifier)
else:
song_info = self.__download_title(song.identifier)
if Utils.is_url(song.identifier):
song_info = self.__download_url(song.identifier)
else:
song_info = self.__download_title(song.identifier)
song.finish_down(song_info)
return song
song.finish_down(song_info)
return song
# Convert yt_dlp error to my own error
except DownloadError:
raise DownloadingError()
async def preload(self, songs: List[Song]) -> None:
for song in songs:
@ -81,8 +86,11 @@ class Downloader:
else: # Failed to extract the songs
print(f'DEVELOPER NOTE -> Failed to Extract URL {url}')
return []
# Convert the yt_dlp download error to own error
except DownloadError:
raise DownloadingError()
except Exception as e:
print(f'DEVELOPER NOTE -> Error Extracting Music: {e}')
print(f'DEVELOPER NOTE -> Error Extracting Music: {e}, {type(e)}')
raise e
else:
return []

View File

@ -1,116 +0,0 @@
import asyncio
from discord.ext import commands
from discord import Client, Guild, FFmpegPCMAudio
from discord.ext.commands import Context
from Music.Downloader import Downloader
from Music.Playlist import Playlist
from Music.Song import Song
from Utils.Utils import Timer
class Player(commands.Cog):
def __init__(self, bot: Client, guild: Guild):
self.__down: Downloader = Downloader()
self.__playlist: Playlist = Playlist()
self.__bot: Client = bot
self.__guild: Guild = guild
self.__timer = Timer(self.__timeout_handler)
self.__playing = False
# Flag to control if the player should stop totally the playing
self.__force_stop = False
self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
'options': '-vn'}
@property
def playing(self) -> bool:
return self.__playing
@property
def playlist(self) -> Playlist:
return self.__playlist
async def play(self, ctx: Context) -> str:
if not self.__playing:
first_song = self.__playlist.next_song()
await self.__play_music(ctx, first_song)
async def play_prev(self, ctx: Context) -> None:
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.__force_stop = True
self.__guild.voice_client.stop()
self.__playing = False
await self.__play_music(ctx, song)
async def force_stop(self) -> None:
try:
if self.__guild.voice_client is None:
return
self.__guild.voice_client.stop()
await self.__guild.voice_client.disconnect()
self.__playlist.clear()
self.__playlist.loop_off()
except Exception as e:
print(f'DEVELOPER NOTE -> Force Stop Error: {e}')
def __play_next(self, error, ctx: Context) -> None:
if self.__force_stop: # If it's forced to stop player
self.__force_stop = False
return None
song = self.__playlist.next_song()
if song is not None:
coro = self.__play_music(ctx, song)
self.__bot.loop.create_task(coro)
else:
self.__playing = False
async def __play_music(self, ctx: Context, song: Song) -> None:
try:
source = await self.__ensure_source(song)
if source is None:
self.__play_next(None, ctx)
self.__playing = True
player = FFmpegPCMAudio(song.source, **self.FFMPEG_OPTIONS)
voice = self.__guild.voice_client
voice.play(player, after=lambda e: self.__play_next(e, ctx))
self.__timer.cancel()
self.__timer = Timer(self.__timeout_handler)
await ctx.invoke(self.__bot.get_command('np'))
songs = self.__playlist.getSongsToPreload()
asyncio.create_task(self.__down.preload(songs))
except:
self.__play_next(None, ctx)
async def __timeout_handler(self) -> None:
if self.__guild.voice_client is None:
return
if self.__guild.voice_client.is_playing() or self.__guild.voice_client.is_paused():
self.__timer = Timer(self.__timeout_handler)
elif self.__guild.voice_client.is_connected():
self.__playlist.clear()
self.__playlist.loop_off()
await self.__guild.voice_client.disconnect()
async def __ensure_source(self, song: Song) -> str:
while True:
await asyncio.sleep(0.1)
if song.source is not None: # If song got downloaded
return song.source
if song.problematic: # If song got any error
return None

View File

@ -44,6 +44,9 @@ class Playlist:
def getCurrentSong(self) -> Song:
return self.__current
def setCurrentSong(self, song: Song) -> Song:
self.__current = song
def getSongsToPreload(self) -> List[Song]:
return list(self.__queue)[:self.__configs.MAX_PRELOAD_SONGS]
@ -73,6 +76,7 @@ class Playlist:
# Get the new song
if len(self.__queue) == 0:
self.__current = None
return None
self.__current = self.__queue.popleft()

View File

@ -1,4 +1,4 @@
from Config.Exceptions import DeezerError, InvalidInput, SpotifyError, YoutubeError
from Config.Exceptions import DeezerError, InvalidInput, SpotifyError, VulkanError, YoutubeError
from Music.Downloader import Downloader
from Music.Types import Provider
from Music.SpotifySearcher import SpotifySearch
@ -25,7 +25,10 @@ class Searcher():
track = self.__cleanYoutubeInput(track)
musics = await self.__down.extract_info(track)
return musics
except:
except VulkanError as error:
raise error
except Exception as error:
print(f'[Error in Searcher] -> {error}, {type(error)}')
raise YoutubeError(self.__messages.YOUTUBE_NOT_FOUND, self.__messages.GENERIC_TITLE)
elif provider == Provider.Spotify:

View File

@ -23,6 +23,7 @@ class Song:
else:
print(f'DEVELOPER NOTE -> {key} not found in info of music: {self.identifier}')
self.destroy()
return
for key in self.__useful_keys:
if key in info.keys():

View File

@ -2,14 +2,16 @@ import asyncio
from os import listdir
from discord import Intents, User, Member
from asyncio import AbstractEventLoop, Semaphore
from multiprocessing import Process, Queue
from multiprocessing import Process, Queue, RLock
from threading import Lock, Thread
from typing import Callable, List
from discord import Client, Guild, FFmpegPCMAudio, VoiceChannel, TextChannel
from Music.Playlist import Playlist
from Music.Song import Song
from Config.Configs import Configs
from Config.Messages import Messages
from discord.ext.commands import Bot
from Views.Embeds import Embeds
from Parallelism.Commands import VCommands, VCommandsType
@ -37,7 +39,8 @@ class PlayerProcess(Process):
Process.__init__(self, name=name, group=None, target=None, args=(), kwargs={})
# Synchronization objects
self.__playlist: Playlist = playlist
self.__lock: Lock = lock
self.__playlistLock: Lock = lock
self.__playerLock: RLock = None
self.__queue: Queue = queue
self.__semStopPlaying: Semaphore = None
self.__loop: AbstractEventLoop = None
@ -55,6 +58,8 @@ class PlayerProcess(Process):
self.__botMember: Member = None
self.__configs: Configs = None
self.__embeds: Embeds = None
self.__messages: Messages = None
self.__playing = False
self.__forceStop = False
self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
@ -64,11 +69,14 @@ class PlayerProcess(Process):
"""Method called by process.start(), this will exec the actually _run method in a event loop"""
try:
print(f'Starting Process {self.name}')
self.__playerLock = RLock()
self.__loop = asyncio.get_event_loop()
self.__configs = Configs()
self.__messages = Messages()
self.__embeds = Embeds()
self.__semStopPlaying = Semaphore(0)
self.__stopped = asyncio.Event()
self.__loop.run_until_complete(self._run())
except Exception as e:
print(f'[Error in Process {self.name}] -> {e}')
@ -100,12 +108,14 @@ class PlayerProcess(Process):
async def __playPlaylistSongs(self) -> None:
if not self.__playing:
with self.__lock:
with self.__playlistLock:
song = self.__playlist.next_song()
await self.__playSong(song)
if song is not None:
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
async def __playSong(self, song: Song) -> None:
"""Function that will trigger the player to play the song"""
try:
if song is None:
return
@ -113,36 +123,46 @@ class PlayerProcess(Process):
if song.source is None:
return self.__playNext(None)
# If not connected, connect to bind channel
if self.__guild.voice_client is None:
self.__connectToVoiceChannel()
# If the player is already playing return
if self.__guild.voice_client.is_playing():
return
self.__playing = True
player = FFmpegPCMAudio(song.source, **self.FFMPEG_OPTIONS)
voice = self.__guild.voice_client
voice.play(player, after=lambda e: self.__playNext(e))
self.__guild.voice_client.play(player, after=lambda e: self.__playNext(e))
self.__timer.cancel()
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
# await self.__context.invoke(self.__bot.get_command('np'))
await self.__showNowPlaying()
except Exception as e:
print(f'[ERROR IN PLAY SONG] -> {e}')
print(f'[ERROR IN PLAY SONG] -> {e}, {type(e)}')
self.__playNext(None)
def __playNext(self, error) -> None:
if self.__forceStop: # If it's forced to stop player
self.__forceStop = False
return None
with self.__playerLock:
if self.__forceStop: # If it's forced to stop player
self.__forceStop = False
return None
with self.__lock:
song = self.__playlist.next_song()
with self.__playlistLock:
song = self.__playlist.next_song()
if song is not None:
coro = self.__playSong(song)
self.__bot.loop.create_task(coro)
else:
self.__playing = False
if song is not None:
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
else:
with self.__playlistLock:
self.__playlist.loop_off()
self.__playing = False
async def __playPrev(self, voiceChannelID: int) -> None:
with self.__lock:
with self.__playlistLock:
song = self.__playlist.prev_song()
if song is not None:
@ -158,7 +178,7 @@ class PlayerProcess(Process):
self.__guild.voice_client.stop()
self.__playing = False
await self.__playSong(song)
self.__loop.create_task(self.__playSong(song), name=f'Song {song.identifier}')
def __commandsReceiver(self) -> None:
while True:
@ -166,23 +186,28 @@ class PlayerProcess(Process):
type = command.getType()
args = command.getArgs()
print(f'Process {self.name} receive Command: {type} with Args: {args}')
if type == VCommandsType.PAUSE:
self.__pause()
elif type == VCommandsType.PLAY:
self.__loop.create_task(self.__playPlaylistSongs())
elif type == VCommandsType.PREV:
self.__loop.create_task(self.__playPrev(args))
elif type == VCommandsType.RESUME:
self.__resume()
elif type == VCommandsType.SKIP:
self.__skip()
elif type == VCommandsType.RESET:
self.__loop.create_task(self.__reset())
elif type == VCommandsType.STOP:
self.__loop.create_task(self.__stop())
else:
print(f'[ERROR] -> Unknown Command Received: {command}')
try:
self.__playerLock.acquire()
if type == VCommandsType.PAUSE:
self.__pause()
elif type == VCommandsType.RESUME:
self.__resume()
elif type == VCommandsType.SKIP:
self.__skip()
elif type == VCommandsType.PLAY:
asyncio.run_coroutine_threadsafe(self.__playPlaylistSongs(), self.__loop)
elif type == VCommandsType.PREV:
asyncio.run_coroutine_threadsafe(self.__playPrev(args), self.__loop)
elif type == VCommandsType.RESET:
asyncio.run_coroutine_threadsafe(self.__reset(), self.__loop)
elif type == VCommandsType.STOP:
asyncio.run_coroutine_threadsafe(self.__stop(), self.__loop)
else:
print(f'[ERROR] -> Unknown Command Received: {command}')
except Exception as e:
print(f'[ERROR IN COMMAND RECEIVER] -> {type} - {e}')
finally:
self.__playerLock.release()
def __pause(self) -> None:
if self.__guild.voice_client is not None:
@ -204,7 +229,7 @@ class PlayerProcess(Process):
async def __stop(self) -> None:
if self.__guild.voice_client is not None:
if self.__guild.voice_client.is_connected():
with self.__lock:
with self.__playlistLock:
self.__playlist.clear()
self.__playlist.loop_off()
self.__guild.voice_client.stop()
@ -220,17 +245,14 @@ class PlayerProcess(Process):
self.__guild.voice_client.stop()
async def __forceStop(self) -> None:
try:
if self.__guild.voice_client is None:
return
if self.__guild.voice_client is None:
return
self.__guild.voice_client.stop()
await self.__guild.voice_client.disconnect()
with self.__lock:
self.__playlist.clear()
self.__playlist.loop_off()
except Exception as e:
print(f'DEVELOPER NOTE -> Force Stop Error: {e}')
self.__guild.voice_client.stop()
await self.__guild.voice_client.disconnect()
with self.__playlistLock:
self.__playlist.clear()
self.__playlist.loop_off()
async def __createBotInstance(self) -> Client:
"""Load a new bot instance that should not be directly called.
@ -268,12 +290,14 @@ class PlayerProcess(Process):
self.__timer = TimeoutClock(self.__timeoutHandler, self.__loop)
elif self.__guild.voice_client.is_connected():
with self.__lock:
self.__playerLock.acquire()
with self.__playlistLock:
self.__playlist.clear()
self.__playlist.loop_off()
self.__playing = False
await self.__guild.voice_client.disconnect()
# Release semaphore to finish process
self.__playerLock.release()
self.__semStopPlaying.release()
except Exception as e:
print(f'[Error in Timeout] -> {e}')
@ -307,3 +331,20 @@ class PlayerProcess(Process):
for member in guild_members:
if member.id == self.__bot.user.id:
return member
async def __showNowPlaying(self) -> None:
# Get the current process of the guild
with self.__playlistLock:
if not self.__playing or self.__playlist.getCurrentSong() 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.__playlist.getCurrentSong().info
embed = self.__embeds.SONG_INFO(info, title)
await self.__textChannel.send(embed=embed)

View File

@ -13,6 +13,9 @@ class ProcessInfo:
self.__playlist = playlist
self.__lock = lock
def setProcess(self, newProcess: Process) -> None:
self.__process = newProcess
def getProcess(self) -> Process:
return self.__process

View File

@ -23,29 +23,30 @@ class ProcessManager(Singleton):
self.__playersProcess: Dict[Guild, ProcessInfo] = {}
def setPlayerContext(self, guild: Guild, context: ProcessInfo):
self.__playersProcess[guild] = context
self.__playersProcess[guild.id] = context
def getPlayerContext(self, guild: Guild, context: Context) -> ProcessInfo:
def getPlayerInfo(self, guild: Guild, context: Context) -> ProcessInfo:
"""Return the process info for the guild, if not, create one"""
try:
if guild not in self.__playersProcess.keys():
self.__playersProcess[guild] = self.__createProcess(context)
if guild.id not in self.__playersProcess.keys():
self.__playersProcess[guild.id] = self.__createProcessInfo(context)
else:
if not self.__playersProcess[guild].getProcess().is_alive():
self.__playersProcess[guild] = self.__createProcess(context)
# 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)
return self.__playersProcess[guild]
return self.__playersProcess[guild.id]
except Exception as e:
print(f'[Error In GetPlayerContext] -> {e}')
def getRunningPlayerInfo(self, guild: Guild) -> ProcessInfo:
"""Return the process info for the guild, if not, return None"""
if guild not in self.__playersProcess.keys():
if guild.id not in self.__playersProcess.keys():
return None
return self.__playersProcess[guild]
return self.__playersProcess[guild.id]
def __createProcess(self, context: Context):
def __createProcessInfo(self, context: Context) -> ProcessInfo:
guildID: int = context.guild.id
textID: int = context.channel.id
voiceID: int = context.author.voice.channel.id
@ -60,6 +61,23 @@ class ProcessManager(Singleton):
return processInfo
def __recreateProcess(self, context: Context) -> 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
playlist: Playlist = self.__playersProcess[guildID].getPlaylist()
lock = Lock()
queue = Queue()
process = PlayerProcess(context.guild.name, playlist, lock, queue,
guildID, textID, voiceID, authorID)
processInfo = ProcessInfo(process, queue, playlist, lock)
return processInfo
class VManager(BaseManager):
pass

View File

@ -32,19 +32,6 @@ class Utils:
return False
class Timer:
def __init__(self, callback):
self.__callback = callback
self.__task = asyncio.create_task(self.__executor())
async def __executor(self):
await asyncio.sleep(config.VC_TIMEOUT)
await self.__callback()
def cancel(self):
self.__task.cancel()
def run_async(func):
@wraps(func)
async def run(*args, loop=None, executor=None, **kwargs):