Modifying play and prev commands to work with Process

This commit is contained in:
Rafael Vargas
2022-07-23 15:51:13 -03:00
parent 7efed8ab89
commit 56456bf2ed
20 changed files with 178 additions and 150 deletions

View File

@@ -12,11 +12,11 @@ class ClearHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
# Get the current process of the guild
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo:
# Clear the playlist
playlist = processContext.getPlaylist()
with processContext.getLock():
playlist = processInfo.getPlaylist()
with processInfo.getLock():
playlist.clear()
return HandlerResponse(self.ctx)

View File

@@ -13,10 +13,10 @@ class HistoryHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
# Get the current process of the guild
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext:
with processContext.getLock():
playlist = processContext.getPlaylist()
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo:
with processInfo.getLock():
playlist = processInfo.getPlaylist()
history = playlist.getSongsHistory()
else:
history = []

View File

@@ -13,15 +13,15 @@ class LoopHandler(AbstractHandler):
async def run(self, args: str) -> HandlerResponse:
# Get the current process of the guild
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if not processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if not processInfo:
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
return HandlerResponse(self.ctx, embed, error)
playlist = processContext.getPlaylist()
playlist = processInfo.getPlaylist()
with processContext.getLock():
with processInfo.getLock():
if args == '' or args is None:
playlist.loop_all()
embed = self.embeds.LOOP_ALL_ACTIVATED()

View File

@@ -14,19 +14,19 @@ class MoveHandler(AbstractHandler):
async def run(self, pos1: str, pos2: str) -> HandlerResponse:
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if not processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if not processInfo:
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
return HandlerResponse(self.ctx, embed, error)
with processContext.getLock():
with processInfo.getLock():
error = self.__validateInput(pos1, pos2)
if error:
embed = self.embeds.ERROR_EMBED(error.message)
return HandlerResponse(self.ctx, embed, error)
playlist = processContext.getPlaylist()
playlist = processInfo.getPlaylist()
pos1, pos2 = self.__sanitizeInput(playlist, pos1, pos2)
if not playlist.validate_position(pos1) or not playlist.validate_position(pos2):

View File

@@ -14,12 +14,12 @@ class NowPlayingHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
# Get the current process of the guild
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if not processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if not processInfo:
embed = self.embeds.NOT_PLAYING()
return HandlerResponse(self.ctx, embed)
playlist = processContext.getPlaylist()
playlist = processInfo.getPlaylist()
if playlist.getCurrentSong() is None:
embed = self.embeds.NOT_PLAYING()
return HandlerResponse(self.ctx, embed)

View File

@@ -12,11 +12,11 @@ class PauseHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo:
# Send Pause command to be execute by player process
command = VCommands(VCommandsType.PAUSE, None)
queue = processContext.getQueue()
queue = processInfo.getQueue()
queue.put(command)
return HandlerResponse(self.ctx)

View File

@@ -1,3 +1,5 @@
import asyncio
from typing import List
from Config.Exceptions import DownloadingError, InvalidInput, VulkanError
from discord.ext.commands import Context
from discord import Client
@@ -8,6 +10,7 @@ from Music.Downloader import Downloader
from Music.Searcher import Searcher
from Music.Song import Song
from Parallelism.ProcessManager import ProcessManager
from Parallelism.ProcessInfo import ProcessInfo
from Parallelism.Commands import VCommands, VCommandsType
@@ -27,55 +30,56 @@ class PlayHandler(AbstractHandler):
return HandlerResponse(self.ctx, embed, error)
try:
musics = await self.__searcher.search(track)
if musics is None or len(musics) == 0:
# Search for musics and get the name of each song
musicsInfo = await self.__searcher.search(track)
if musicsInfo is None or len(musicsInfo) == 0:
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
manager = ProcessManager()
processContext = manager.getPlayerContext(self.guild, self.ctx)
# Add the downloaded song to the process playlist
# All access to shared memory should be protect by acquire the Lock
with processContext.getLock():
processContext.getPlaylist().add_song(song)
# 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
processInfo = manager.getPlayerContext(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()
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:
if isinstance(err, VulkanError): # If error was already processed
@@ -89,6 +93,25 @@ class PlayHandler(AbstractHandler):
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:
if self.ctx.author.voice:
return True

View File

@@ -1,8 +1,10 @@
from discord.ext.commands import Context
from discord import Client
from Handlers.AbstractHandler import AbstractHandler
from Config.Exceptions import BadCommandUsage, ImpossibleMove, UnknownError
from Config.Exceptions import BadCommandUsage, ImpossibleMove
from Handlers.HandlerResponse import HandlerResponse
from Parallelism.ProcessManager import ProcessManager
from Parallelism.Commands import VCommands, VCommandsType
class PrevHandler(AbstractHandler):
@@ -10,7 +12,15 @@ class PrevHandler(AbstractHandler):
super().__init__(ctx, bot)
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()
embed = self.embeds.NOT_PREVIOUS_SONG()
return HandlerResponse(self.ctx, embed, error)
@@ -20,41 +30,18 @@ class PrevHandler(AbstractHandler):
embed = self.embeds.NO_CHANNEL()
return HandlerResponse(self.ctx, embed, error)
if not self.__is_connected():
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():
if playlist.isLoopingAll() or playlist.isLoopingOne():
error = BadCommandUsage()
embed = self.embeds.FAIL_DUE_TO_LOOP_ON()
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:
if self.ctx.author.voice:
return True
else:
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

View File

@@ -16,14 +16,14 @@ class QueueHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
# Retrieve the process of the guild
process = ProcessManager()
processContext = process.getRunningPlayerContext(self.guild)
if not processContext: # If no process return empty list
processInfo = process.getRunningPlayerInfo(self.guild)
if not processInfo: # If no process return empty list
embed = self.embeds.EMPTY_QUEUE()
return HandlerResponse(self.ctx, embed)
# Acquire the Lock to manipulate the playlist
with processContext.getLock():
playlist = processContext.getPlaylist()
with processInfo.getLock():
playlist = processInfo.getPlaylist()
if playlist.isLoopingOne():
song = playlist.getCurrentSong()
@@ -31,6 +31,7 @@ class QueueHandler(AbstractHandler):
return HandlerResponse(self.ctx, embed)
songs_preload = playlist.getSongsToPreload()
allSongs = playlist.getSongs()
if len(songs_preload) == 0:
embed = self.embeds.EMPTY_QUEUE()
return HandlerResponse(self.ctx, embed)
@@ -43,7 +44,7 @@ class QueueHandler(AbstractHandler):
title = self.messages.QUEUE_TITLE
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())
text = f'📜 Queue length: {total_songs} | ⌛ Duration: `{total_time}` downloaded \n\n'

View File

@@ -15,14 +15,14 @@ class RemoveHandler(AbstractHandler):
async def run(self, position: str) -> HandlerResponse:
# Get the current process of the guild
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if not processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if not processInfo:
# Clear the playlist
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
return HandlerResponse(self.ctx, embed, error)
playlist = processContext.getPlaylist()
playlist = processInfo.getPlaylist()
if playlist.getCurrentSong() is None:
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
@@ -60,5 +60,5 @@ class RemoveHandler(AbstractHandler):
position = int(position)
if position == -1:
position = len(playlist)
position = len(playlist.getSongs())
return position

View File

@@ -13,10 +13,10 @@ class ResetHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
# Get the current process of the guild
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo:
command = VCommands(VCommandsType.RESET, None)
queue = processContext.getQueue()
queue = processInfo.getQueue()
queue.put(command)
return HandlerResponse(self.ctx)

View File

@@ -12,11 +12,11 @@ class ResumeHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo:
# Send Resume command to be execute by player process
command = VCommands(VCommandsType.RESUME, None)
queue = processContext.getQueue()
queue = processInfo.getQueue()
queue.put(command)
return HandlerResponse(self.ctx)

View File

@@ -12,11 +12,11 @@ class ShuffleHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo:
try:
with processContext.getLock():
playlist = processContext.getPlaylist()
with processInfo.getLock():
playlist = processInfo.getPlaylist()
playlist.shuffle()
embed = self.embeds.SONGS_SHUFFLED()

View File

@@ -13,9 +13,9 @@ class SkipHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext: # Verify if there is a running process
playlist = processContext.getPlaylist()
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo: # Verify if there is a running process
playlist = processInfo.getPlaylist()
if playlist.isLoopingOne():
embed = self.embeds.ERROR_DUE_LOOP_ONE_ON()
error = BadCommandUsage()
@@ -23,6 +23,6 @@ class SkipHandler(AbstractHandler):
# Send a command to the player process to skip the music
command = VCommands(VCommandsType.SKIP, None)
queue = processContext.getQueue()
queue = processInfo.getQueue()
queue.put(command)
return HandlerResponse(self.ctx)

View File

@@ -12,11 +12,11 @@ class StopHandler(AbstractHandler):
async def run(self) -> HandlerResponse:
processManager = ProcessManager()
processContext = processManager.getRunningPlayerContext(self.guild)
if processContext:
processInfo = processManager.getRunningPlayerInfo(self.guild)
if processInfo:
# Send command to player process stop
command = VCommands(VCommandsType.STOP, None)
queue = processContext.getQueue()
queue = processInfo.getQueue()
queue.put(command)
return HandlerResponse(self.ctx)