Adding volume change command, pre-release

This commit is contained in:
Rafael Vargas 2023-06-24 22:05:23 -03:00
parent fc02cab769
commit 2114f15840
10 changed files with 180 additions and 3 deletions

View File

@ -343,6 +343,13 @@ class VEmbeds:
description=self.__messages.PLAYER_NOT_PLAYING,
colour=self.__colors.BLUE)
return embed
def VOLUME_CHANGED(self, volume: float) -> Embed:
embed = Embed(
title=self.__messages.SONG_PLAYER,
description=self.__messages.VOLUME_CHANGED.format(volume),
colour=self.__colors.BLUE)
return embed
def QUEUE(self, title: str, description: str) -> Embed:
embed = Embed(

View File

@ -30,6 +30,8 @@ class Helper(Singleton):
self.HELP_SHUFFLE = 'Shuffle the songs playing.'
self.HELP_SHUFFLE_LONG = 'Randomly shuffle the songs in the queue.\n\nArguments: None.'
self.HELP_PLAY = 'Plays a song from URL'
self.CHANGE_VOLUME = '**[Pre-release]** - Set the volume of the song'
self.CHANGE_VOLUME_LONG = '**[Pre-release]** - Change the volume of the song, expect a number from 0 to 100'
self.HELP_PLAY_LONG = 'Play a song in discord. \n\nRequire: You to be connected to a voice channel.\nArguments: Youtube, Spotify or Deezer song/playlist link or the title of the song to be searched in Youtube.'
self.HELP_HISTORY = f'Show the history of played songs.'
self.HELP_HISTORY_LONG = f'Show the last {config.MAX_SONGS_HISTORY} played songs'

View File

@ -16,6 +16,7 @@ class Messages(Singleton):
self.SONGINFO_REQUESTER = 'Requester: '
self.SONGINFO_POSITION = 'Position: '
self.VOLUME_CHANGED = '**[Pre-release]** - Song volume changed to `{}`%'
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 = f'{self.__emojis.MUSIC} Song added to the queue'
@ -56,6 +57,7 @@ class Messages(Singleton):
self.ERROR_MOVING = f'{self.__emojis.ERROR} Error while moving the songs'
self.LENGTH_ERROR = f'{self.__emojis.ERROR} Numbers must be between 1 and queue length, use -1 for the last song'
self.ERROR_NUMBER = f'{self.__emojis.ERROR} This command require a number'
self.ERROR_VOLUME_NUMBER = f'{self.__emojis.ERROR} This command require a number between 0 and 100'
self.ERROR_PLAYING = f'{self.__emojis.ERROR} Error while playing songs'
self.COMMAND_NOT_FOUND = f'{self.__emojis.ERROR} Command not found, type {configs.BOT_PREFIX}help to see all commands'
self.UNKNOWN_ERROR = f'{self.__emojis.ERROR} Unknown Error, if needed, use {configs.BOT_PREFIX}reset to reset the player of your server'

View File

@ -21,7 +21,7 @@ class ControlCog(Cog):
'MUSIC': ['resume', 'pause', 'loop', 'stop',
'skip', 'play', 'queue', 'clear',
'np', 'shuffle', 'move', 'remove',
'reset', 'prev', 'history'],
'reset', 'prev', 'history', 'volume'],
'RANDOM': ['choose', 'cara', 'random']
}

View File

@ -17,6 +17,7 @@ from Handlers.ResumeHandler import ResumeHandler
from Handlers.HistoryHandler import HistoryHandler
from Handlers.QueueHandler import QueueHandler
from Handlers.LoopHandler import LoopHandler
from Handlers.VolumeHandler import VolumeHandler
from Messages.MessagesCategory import MessagesCategory
from Messages.Responses.EmoteCogResponse import EmoteCommandResponse
from Messages.Responses.EmbedCogResponse import EmbedCommandResponse
@ -64,6 +65,25 @@ class MusicCog(Cog):
except Exception as e:
print(f'[ERROR IN COG] -> {e}')
@command(name="volume", help=helper.CHANGE_VOLUME, description=helper.CHANGE_VOLUME_LONG, aliases=['v'])
async def volume(self, ctx: Context, *args) -> None:
try:
controller = VolumeHandler(ctx, self.__bot)
if len(args) > 1:
track = " ".join(args)
else:
track = args[0]
response = await controller.run(track)
if response is not None:
cogResponser1 = EmbedCommandResponse(response, MessagesCategory.PLAYER)
cogResponser2 = EmoteCommandResponse(response, MessagesCategory.PLAYER)
await cogResponser1.run()
await cogResponser2.run()
except Exception as e:
print(f'[ERROR IN COG] -> {e}')
@command(name="queue", help=helper.HELP_QUEUE, description=helper.HELP_QUEUE_LONG, aliases=['q', 'fila', 'musicas'])
async def queue(self, ctx: Context, *args) -> None:
try:

View File

@ -15,6 +15,7 @@ from Handlers.ResumeHandler import ResumeHandler
from Handlers.HistoryHandler import HistoryHandler
from Handlers.QueueHandler import QueueHandler
from Handlers.LoopHandler import LoopHandler
from Handlers.VolumeHandler import VolumeHandler
from Messages.MessagesCategory import MessagesCategory
from Messages.Responses.SlashEmbedResponse import SlashEmbedResponse
from Music.VulkanBot import VulkanBot
@ -237,6 +238,22 @@ class SlashCommands(Cog):
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')
@slash_command(name='volume', description=helper.CHANGE_VOLUME_LONG)
async def move(self, ctx: ApplicationContext,
volume: Option(float, "The new volume of the song", min_value=1, default= 100)) -> None:
if not self.__bot.listingSlash:
return
try:
await ctx.defer()
controller = VolumeHandler(ctx, self.__bot)
response = await controller.run(f'{volume}')
cogResponser = SlashEmbedResponse(response, ctx, MessagesCategory.PLAYER)
await cogResponser.run()
except Exception:
print(f'[ERROR IN SLASH COMMAND] -> {traceback.format_exc()}')
@slash_command(name='remove', description=helper.HELP_REMOVE)
async def remove(self, ctx: ApplicationContext,
position: Option(int, "The song position to remove", min_value=1)) -> None:

62
Handlers/VolumeHandler.py Normal file
View File

@ -0,0 +1,62 @@
from Config.Exceptions import BadCommandUsage, NumberRequired, VulkanError
from Parallelism.AbstractProcessManager import AbstractPlayersManager
from Parallelism.Commands import VCommands, VCommandsType
from Handlers.AbstractHandler import AbstractHandler
from Handlers.HandlerResponse import HandlerResponse
from discord.ext.commands import Context
from Music.VulkanBot import VulkanBot
from discord import Interaction
from typing import Union
class VolumeHandler(AbstractHandler):
def __init__(self, ctx: Union[Context, Interaction], bot: VulkanBot) -> None:
super().__init__(ctx, bot)
async def run(self, args: str) -> HandlerResponse:
if args is None or args.strip() == '':
error = BadCommandUsage()
return HandlerResponse(self.ctx, embed, error)
error = self.__validateInput(args)
if error:
embed = self.embeds.ERROR_EMBED(error.message)
return HandlerResponse(self.ctx, embed, error)
playersManager: AbstractPlayersManager = self.config.getPlayersManager()
if not playersManager.verifyIfPlayerExists(self.guild):
embed = self.embeds.NOT_PLAYING()
error = BadCommandUsage()
return HandlerResponse(self.ctx, embed, error)
playerLock = playersManager.getPlayerLock(self.guild)
acquired = playerLock.acquire(timeout=self.config.ACQUIRE_LOCK_TIMEOUT)
volume = self.__convert_input_to_volume(args)
if acquired:
volumeCommand = VCommands(VCommandsType.VOLUME, volume)
await playersManager.sendCommandToPlayer(volumeCommand, self.guild, self.ctx)
playerLock.release()
embed = self.embeds.VOLUME_CHANGED(volume)
return HandlerResponse(self.ctx, embed)
else:
playersManager.resetPlayer(self.guild, self.ctx)
embed = self.embeds.PLAYER_RESTARTED()
return HandlerResponse(self.ctx, embed)
def __convert_input_to_volume(self, input_volume: str) -> float:
volume = float(input_volume)
if volume < 0:
volume = 0
if volume > 100:
volume = 100
return volume
def __validateInput(self, volume: str) -> Union[VulkanError, None]:
try:
_ = float(volume)
except:
return NumberRequired(self.messages.ERROR_VOLUME_NUMBER)

View File

@ -13,6 +13,7 @@ class VCommandsType(Enum):
RESET = 'Reset'
NOW_PLAYING = 'Now Playing'
TERMINATE = 'Terminate'
VOLUME = 'Volume'
SLEEPING = 'Sleeping'

View File

@ -2,7 +2,7 @@ import asyncio
from time import sleep, time
from urllib.parse import parse_qs, urlparse
from Music.VulkanInitializer import VulkanInitializer
from discord import VoiceClient
from discord import PCMVolumeTransformer, VoiceClient
from asyncio import AbstractEventLoop, Semaphore, Queue
from multiprocessing import Process, RLock, Lock, Queue
from threading import Thread
@ -54,6 +54,7 @@ class ProcessPlayer(Process):
self.__voiceChannel: VoiceChannel = None
self.__voiceClient: VoiceClient = None
self.__currentSongChangeVolume = False
self.__playing = False
self.__forceStop = False
self.__botCompletedLoad = False
@ -98,6 +99,31 @@ class ProcessPlayer(Process):
# In this point the process should finalize
self.__timer.cancel()
def __set_volume(self, volume: float) -> None:
"""Set the volume of the player, must be values between 0 and 100"""
try:
if self.__voiceClient is None:
return
if not isinstance(volume, float):
print('[PROCESS ERROR] -> Volume instance must be float')
return
if volume < 0:
volume = 0
if volume > 100:
volume = 100
volume = volume / 100
if not self.__currentSongChangeVolume:
print('[PROCESS ERROR] -> Cannot change the volume of this song')
return
self.__voiceClient.source.volume = volume
except Exception as e:
print(e)
def __verifyIfIsPlaying(self) -> bool:
if self.__voiceClient is None:
return False
@ -151,6 +177,10 @@ class ProcessPlayer(Process):
self.__songPlaying = song
player = FFmpegPCMAudio(song.source, **self.FFMPEG_OPTIONS)
if not player.is_opus():
player = PCMVolumeTransformer(player, 1)
self.__currentSongChangeVolume = True
self.__voiceClient.play(player, after=lambda e: self.__playNext(e))
self.__timer.cancel()
@ -169,6 +199,8 @@ class ProcessPlayer(Process):
print(f'[PROCESS PLAYER -> ERROR PLAYING SONG] -> {error}')
with self.__playlistLock:
with self.__playerLock:
self.__currentSongChangeVolume = False
if self.__forceStop: # If it's forced to stop player
self.__forceStop = False
return None
@ -271,6 +303,8 @@ class ProcessPlayer(Process):
asyncio.run_coroutine_threadsafe(self.__reset(), self.__loop)
elif type == VCommandsType.STOP:
asyncio.run_coroutine_threadsafe(self.__stop(), self.__loop)
elif type == VCommandsType.VOLUME:
self.__set_volume(args)
else:
print(f'[PROCESS PLAYER ERROR] -> Unknown Command Received: {command}')
except Exception as e:

View File

@ -1,7 +1,7 @@
import asyncio
from time import time
from urllib.parse import parse_qs, urlparse
from discord import VoiceClient
from discord import PCMVolumeTransformer, VoiceClient
from asyncio import AbstractEventLoop
from threading import RLock, Thread
from multiprocessing import Lock
@ -45,6 +45,7 @@ class ThreadPlayer(Thread):
self.__voiceChannel: VoiceChannel = voiceChannel
self.__voiceClient: VoiceClient = None
self.__currentSongChangeVolume = False
self.__downloader = Downloader()
self.__callback = callbackToSendCommand
self.__exitCB = exitCB
@ -56,6 +57,31 @@ class ThreadPlayer(Thread):
self.FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
'options': '-vn'}
def __set_volume(self, volume: float) -> None:
"""Set the volume of the player, must be values between 0 and 100"""
try:
if self.__voiceClient is None:
return
if not isinstance(volume, float):
print('[THREAD ERROR] -> Volume instance must be float')
return
if volume < 0:
volume = 0
if volume > 100:
volume = 100
volume = volume / 100
if not self.__currentSongChangeVolume:
print('[THREAD ERROR] -> Cannot change the volume of this song')
return
self.__voiceClient.source.volume = volume
except Exception as e:
print(e)
def __verifyIfIsPlaying(self) -> bool:
if self.__voiceClient is None:
return False
@ -109,6 +135,9 @@ class ThreadPlayer(Thread):
self.__songPlaying = song
player = FFmpegPCMAudio(song.source, **self.FFMPEG_OPTIONS)
if not player.is_opus():
player = PCMVolumeTransformer(player, 1)
self.__currentSongChangeVolume = True
self.__voiceClient.play(player, after=lambda e: self.__playNext(e))
self.__timer.cancel()
@ -127,6 +156,7 @@ class ThreadPlayer(Thread):
print(f'[THREAD PLAYER -> ERROR PLAYING SONG] -> {error}')
with self.__playlistLock:
with self.__playerLock:
self.__currentSongChangeVolume = False
if self.__forceStop: # If it's forced to stop player
self.__forceStop = False
return None
@ -217,6 +247,8 @@ class ThreadPlayer(Thread):
await self.__reset()
elif type == VCommandsType.STOP:
await self.__stop()
elif type == VCommandsType.VOLUME:
self.__set_volume(args)
else:
print(f'[THREAD PLAYER ERROR] -> Unknown Command Received: {command}')
except Exception as e: