Add new version of music controller

This commit is contained in:
Rafael Vargas
2021-12-28 20:43:48 -04:00
parent 35f5492b12
commit 7d22998ebc

View File

@@ -1,234 +1,168 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from youtube_dl import YoutubeDL import datetime
import asyncio
from config import config
from vulkanbot.music.Downloader import Downloader from vulkanbot.music.Downloader import Downloader
from vulkanbot.music.Playlist import Playlist
from vulkanbot.music.Searcher import Searcher from vulkanbot.music.Searcher import Searcher
colours = {
'red': 0xDC143C,
'green': 0x00FF7F,
'grey': 0x708090,
'blue': 0x0000CD
}
class Music(commands.Cog): class Music(commands.Cog):
def __init__(self, client): def __init__(self, bot):
self.__searcher = Searcher() self.__searcher = Searcher()
self.__downloader = Downloader() self.__downloader = Downloader()
self.__playlist = Playlist()
self.__playing = False
self.__bot = bot
self.__ffmpeg = 'C:/ffmpeg/bin/ffmpeg.exe'
self.__vc = "" # Objeto voice_bot do discord
self.client = client
self.is_playing = False
self.repetingOne = False
self.repetingAll = False
self.current = ()
# 2d array containing [song, channel]
# self.music_queue vai conter as buscas recebidas feitas no youtube em ordem
# Caminho do executável para rodar na minha máquina
self.ffmpeg = 'C:/ffmpeg/bin/ffmpeg.exe'
# Segue o padrão de [[{'source', 'title'}, canal], [musica, canal]]
self.music_queue = []
self.vc = "" # Objeto voice_client do discord
self.YDL_OPTIONS = {'format': 'bestaudio', 'noplaylist': 'True'} self.YDL_OPTIONS = {'format': 'bestaudio', 'noplaylist': 'True'}
self.FFMPEG_OPTIONS = {'executable': self.ffmpeg, self.FFMPEG_OPTIONS = {'executable': self.__ffmpeg,
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'} 'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
def search_yt(self, item): def __play_next(self):
with YoutubeDL(self.YDL_OPTIONS) as ydl: while True:
try: # Busca um video no youtube e traz o titulo e a fonte dele em formato de dict if len(self.__playlist) > 0:
info = ydl.extract_info("ytsearch:%s" % source = self.__playlist.next_song()
item, download=False)['entries'][0] if source == None: # If there is not a source
continue
except Exception: player = discord.FFmpegPCMAudio(source, **self.FFMPEG_OPTIONS)
return False self.__vc.play(player, after=lambda e: self.__play_next())
# Retorna a fonte e o titulo buscado break
return {'source': info['formats'][0]['url'], 'title': info['title']} else:
self.__playing = False
def play_next(self): break
if len(self.music_queue) > 0:
if self.repetingOne:
# Coloca a musica atual no topo da fila
self.music_queue.insert(0, self.current)
elif self.repetingAll:
# Joga a musica atual para o final da fila
self.music_queue.append(self.current)
self.is_playing = True
source = self.music_queue[0][0]['source']
self.current = self.music_queue[0] # Update current music
self.music_queue.pop(0) # Remove from the queue
player = discord.FFmpegPCMAudio(source, **self.FFMPEG_OPTIONS)
self.vc.play(player, after=lambda e: self.play_next()) # Play
else:
self.is_playing = False
self.repetingAll = False
self.repetingOne = False
# infinite loop checking # infinite loop checking
async def play_music(self): async def __play_music(self):
if len(self.music_queue) > 0: while True:
self.is_playing = True if len(self.__playlist) > 0:
source = self.music_queue[0][0]['source'] source = self.__playlist.next_song()
if source == None:
continue
# Try to connect to voice channel if you are not already connected self.__playing = True
if self.vc == "" or not self.vc.is_connected() or self.vc == None: player = discord.FFmpegPCMAudio(source, **self.FFMPEG_OPTIONS)
# Conecta o voice_client no channel da primeira música da lista self.__vc.play(player, after=lambda e: self.__play_next())
self.vc = await self.music_queue[0][1].connect() break
else: else:
await self.vc.move_to(self.music_queue[0][1]) self.__playing = False
await self.__vc.disconnect()
break
self.current = self.music_queue[0] # Update current music @commands.command(name="play", help="Toca música - YouTube/Spotify/Título", aliases=['p', 'tocar'])
self.music_queue.pop(0) # Remove from the queue async def play(self, ctx, *args):
player = discord.FFmpegPCMAudio(source, **self.FFMPEG_OPTIONS) user_input = " ".join(args)
# Start the player
self.vc.play(player, after=lambda e: self.play_next())
else:
self.is_playing = False
await self.vc.disconnect()
@commands.command(name="help", alisases=['ajuda'], help="Comando de ajuda")
async def ajuda(self, ctx):
helptxt = ''
for command in self.client.commands:
helptxt += f'**{command}** - {command.help}\n'
embedhelp = discord.Embed(
colour=1646116, # grey
title=f'Comandos do {self.client.user.name}',
description=helptxt
)
embedhelp.set_thumbnail(url=self.client.user.avatar_url)
await ctx.send(embed=embedhelp)
@commands.command(name="play", help="Toca uma música do YouTube", aliases=['p', 'tocar'])
async def p(self, ctx, *args):
query = " ".join(args)
try: try:
# Nome do canal de voz que vai entrar if self.__vc == "" or not self.__vc.is_connected() or self.__vc == None:
voice_channel = ctx.author.voice.channel voice_channel = ctx.author.voice.channel
except: self.__vc = await voice_channel.connect()
except Exception as e:
# If voice_channel is None: # If voice_channel is None:
await self.send_embed(ctx, title='Para tocar música, primeiro se conecte a um canal de voz.', colour_name='grey') print(e)
await self.__send_embed(ctx, title='Para tocar música, primeiro se conecte a um canal de voz.', colour_name='grey')
return return
else: else:
song = self.search_yt(query) songs_quant = 0
if type(song) == type(True): # Caso seja retornado um booleano da busca musics_names, provider = self.__searcher.search(user_input)
await self.send_embed(ctx, description='Algo deu errado! Tente escrever o nome da música novamente!', colour_name='red') for music in musics_names:
return music_info = self.__downloader.download_urls(music, provider)
else:
await self.send_embed(ctx, description=f"Você adicionou a música **{song['title']}** à fila!", colour_name='green')
self.music_queue.append([song, voice_channel])
if self.is_playing == False: for music in music_info:
await self.play_music() self.__playlist.add_song(music)
songs_quant += 1
if songs_quant == 1:
await self.__send_embed(ctx, description=f"Você adicionou a música **{music_info[0]['title']}** à fila!", colour_name='green')
else:
await self.__send_embed(ctx, description=f"Você adicionou {songs_quant} músicas à fila!", colour_name='green')
if not self.__playing:
await self.__play_music()
@commands.command(name="queue", help="Mostra as atuais músicas da fila.", aliases=['q', 'fila']) @commands.command(name="queue", help="Mostra as atuais músicas da fila.", aliases=['q', 'fila'])
async def q(self, ctx): async def queue(self, ctx):
fila = "" if self.__playlist.looping_one: # If Repeting one
for x in range(len(self.music_queue)): # Send the current song with this title
fila += f"**{x+1} - ** {self.music_queue[x][0]['title']}\n" await self.this(ctx)
return
if self.repetingOne: # If Repeting one fila = self.__playlist.queue()
await self.send_embed(ctx, title='Repeting One Music', total = len(fila)
description=f'sica: **{self.current[0]["title"]}**', colour_name='green') text = f'Total musics: {total}\n\n'
elif fila != "":
if self.repetingAll: # If repeting all # Create the string to description
await self.send_embed(ctx, title='Repetindo todas', description=fila, colour_name='green') for pos, song in enumerate(fila):
if pos >= config.MAX_QUEUE_LENGTH: # Max songs to apper in queue list
break
text += f"**{pos+1} - ** {song}\n"
if text != "":
if self.__playlist.looping_all: # If repeting all
await self.__send_embed(ctx, title='Repeating all', description=text, colour_name='green')
else: # Repeting off else: # Repeting off
await self.send_embed(ctx, description=fila, colour_name='green') await self.__send_embed(ctx, title='Queue', description=text, colour_name='green')
else: # No music else: # No music
await self.send_embed(ctx, description='Não existem músicas na fila.', colour_name='red') await self.__send_embed(ctx, description='There is not musics in queue.', colour_name='red')
@commands.command(name="skip", help="Pula a atual música que está tocando.", aliases=['pular']) @commands.command(name="skip", help="Pula a atual música que está tocando.", aliases=['pular'])
async def skip(self, ctx): async def skip(self, ctx):
if self.vc != "" and self.vc: if self.__vc != '' and self.__vc:
self.vc.stop() print('Skip')
await self.send_embed(ctx, description=f'Você pulou a música\nRepetindo Uma: {self.repetingOne} \ self.__vc.stop()
\nRepetindo Todas: {self.repetingAll}', colour_name='green')
@commands.command(name='stop', help='Para de tocar músicas') @commands.command(name='stop', help='Para de tocar músicas')
async def stop(self, ctx): async def stop(self, ctx):
if self.vc == '': if self.__vc == '':
return return
if self.vc.is_connected(): if self.__vc.is_connected():
# Remove todas as músicas da lista self.__playlist.clear()
self.music_queue = [] self.__vc.stop()
self.current = () await self.__vc.disconnect()
self.repetingOne = False
self.repetingAll = False
self.is_playing = False
self.vc.stop()
await self.vc.disconnect()
@commands.command(name='pause', help='Pausa a música') @commands.command(name='pause', help='Pausa a música')
async def pause(self, ctx): async def pause(self, ctx):
if self.vc == '': if self.__vc == '':
return return
if self.vc.is_playing(): if self.__vc.is_playing():
self.vc.pause() self.__vc.pause()
await self.send_embed(ctx, description='Música pausada', colour_name='green') await self.__send_embed(ctx, description='Música pausada', colour_name='green')
@commands.command(name='resume', help='Despausa a música atual') @commands.command(name='resume', help='Despausa a música atual')
async def resume(self, ctx): async def resume(self, ctx):
if self.vc == '': if self.__vc == '':
return return
if self.vc.is_paused(): if self.__vc.is_paused():
self.vc.resume() self.__vc.resume()
await self.send_embed(ctx, description='Música tocando', colour_name='green') await self.__send_embed(ctx, description='Música tocando', colour_name='green')
@commands.command(name='repeat_one', help='Repete a música atual') @commands.command(name='loop', help='Controla a repetição de músicas')
async def repeat_one(self, ctx): async def loop(self, ctx, args: str):
if not self.is_playing: # Garante que o Bot está tocando args = args.lower()
await self.send_embed(ctx, title='Vulkan não está tocando agora', colour_name='red') if args == 'one':
return description = self.__playlist.loop_one()
elif args == 'all':
if self.repetingAll: # Verifica se o repeting all não está ligado description = self.__playlist.loop_all()
await self.send_embed(ctx, title='Já está repetindo todas', colour_name='red') elif args == 'off':
return description = self.__playlist.loop_off()
else: # Liga o repeting one
self.repetingOne = True
await self.send_embed(ctx, description='Repetir uma música ligado', colour_name='green')
@commands.command(name='repeat_all', help='Repete toda a fila')
async def repeat_all(self, ctx):
if not self.is_playing: # Garante que o Bot está tocando
await self.send_embed(ctx, title='Vulkan não está tocando agora', colour_name='red')
return
if self.repetingOne: # Verifica se o repeting all não está ligado
await self.send_embed(ctx, title='Já está repetindo uma música', colour_name='red')
return
else: # Liga o repeting one
self.repetingAll = True
await self.send_embed(ctx, description='Repetir todas as músicas ligado', colour_name='green')
@commands.command(name='repeat_off', help='Desativa o repetir músicas')
async def repeat_off(self, ctx):
if not self.is_playing: # Garante que o Bot está tocando
await self.send_embed(ctx, title='Vulkan não está tocando agora', colour_name='red')
return
else: else:
self.repetingOne = False description = 'Comando Loop\nOne - Repete a música atual\nAll - Repete as músicas atuais\nOff - Desativa o loop'
self.repetingAll = False
await self.send_embed(ctx, description='Repetir músicas desligado', colour_name='green')
@skip.error # Erros para kick await self.__send_embed(ctx, description=description, colour_name='grey')
async def skip_error(self, ctx, error):
if isinstance(error, commands.MissingPermissions):
embedvc = discord.Embed(
colour=12255232,
description=f"Você precisa da permissão **Gerenciar canais** para pular músicas."
)
await ctx.send(embed=embedvc)
else:
raise error
async def send_embed(self, ctx, title='', description='', colour_name='red'):
async def __send_embed(self, ctx, title='', description='', colour_name='grey'):
try: try:
colour = colours[colour_name] colour = config.COLOURS[colour_name]
except Exception as e: except Exception as e:
colour = colours['red'] colour = config.COLOURS['grey']
embedvc = discord.Embed( embedvc = discord.Embed(
title=title, title=title,
@@ -237,6 +171,43 @@ class Music(commands.Cog):
) )
await ctx.send(embed=embedvc) await ctx.send(embed=embedvc)
@commands.command(name='clear', help='Limpa a fila de músicas a tocar')
async def clear(self, ctx):
self.__playlist.clear()
def setup(client): @commands.command(name='this', help='Mostra a música que está tocando no instante')
client.add_cog(Music(client)) async def this(self, ctx):
if self.__playlist.looping_one:
title = 'Music Looping Now'
else:
title = 'Music Playing Now'
info = self.__playlist.get_current()
embedvc = discord.Embed(
title=title,
description=f"[{info['title']}]({info['url']})",
color=config.COLOURS['grey']
)
embedvc.add_field(name=config.SONGINFO_UPLOADER,
value=info['uploader'],
inline=False)
if 'thumbnail' in info.keys():
embedvc.set_thumbnail(url=info['thumbnail'])
if 'duration' in info.keys():
duration = str(datetime.timedelta(seconds=info['duration']))
embedvc.add_field(name=config.SONGINFO_DURATION,
value=f"{duration}",
inline=False)
else:
embedvc.add_field(name=config.SONGINFO_DURATION,
value=config.SONGINFO_UNKNOWN_DURATION,
inline=False)
await ctx.send(embed=embedvc)
def setup(bot):
bot.add_cog(Music(bot))