Merge pull request #6 from RafaelSolVargas/fixing-spotify-bug

Adding new Adming Module and Stylish update
This commit is contained in:
Rafael Vargas 2022-01-01 14:32:37 -04:00 committed by GitHub
commit aa4bb00745
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 250 additions and 204 deletions

View File

@ -12,12 +12,13 @@ PHRASES_API = dotenv_values('.env')['PHRASES_API']
BOT_PREFIX = '!' BOT_PREFIX = '!'
INITIAL_EXTENSIONS = {'vulkanbot.commands.Phrases', 'vulkanbot.commands.Warframe', INITIAL_EXTENSIONS = {'vulkanbot.commands.Phrases', 'vulkanbot.commands.Warframe',
'vulkanbot.general.Filter', 'vulkanbot.general.Control', 'vulkanbot.music.Music', 'vulkanbot.general.Filter', 'vulkanbot.general.Control', 'vulkanbot.music.Music',
'vulkanbot.commands.Random'} 'vulkanbot.commands.Random', 'vulkanbot.general.Admin'}
STARTUP_MESSAGE = 'Starting Vulkan...' STARTUP_MESSAGE = 'Starting Vulkan...'
STARTUP_COMPLETE_MESSAGE = 'Vulkan is now operating.' STARTUP_COMPLETE_MESSAGE = 'Vulkan is now operating.'
FFMPEG_PATH = 'C:/ffmpeg/bin/ffmpeg.exe'
MAX_PLAYLIST_LENGTH = 50 MAX_PLAYLIST_LENGTH = 50
MAX_API_PHRASES_TRIES = 10 MAX_API_PHRASES_TRIES = 10
@ -26,9 +27,31 @@ MAX_API_CAMBION_TRIES = 10
MAX_API_FISSURES_TRIES = 10 MAX_API_FISSURES_TRIES = 10
MAX_PRELOAD_SONGS = 10 MAX_PRELOAD_SONGS = 10
TRASH_CHANNEL_ID = 919961802140450837
SONGINFO_UPLOADER = "Uploader: " SONGINFO_UPLOADER = "Uploader: "
SONGINFO_DURATION = "Duration: " SONGINFO_DURATION = "Duration: "
HELP_SKIP = 'Skip the current playing song'
HELP_RESUME = 'Resumes the song player'
HELP_CLEAR = 'Clear the queue'
HELP_STOP = 'Stop the song player, removing Vulkan from voice channel'
HELP_LOOP = '(one/all/off) - Control the loop of songs'
HELP_NP = 'Show the info of the current song'
HELP_QUEUE = f'Show the first {MAX_PRELOAD_SONGS} songs in queue'
HELP_PAUSE = 'Pauses the song player'
HELP_SHUFFLE = 'Shuffle the songs playing'
HELP_PLAY = '(title/youtube/spotify) - Plays a song'
HELP_MOVE = '(x, y) - Moves a song from position x to y in queue'
HELP_WARFRAME = f'({BOT_PREFIX}warframe help for more) - Return warframe information'
HELP_RANDOM = '(x) - Return a random number between 1 and x'
HELP_ESCOLHA = '(x, y, z...) - Choose randomly one item passed in the command'
HELP_CARA = 'Return cara or coroa'
HELP_DROP = '(user_name) - Try to remove the user from the current voice channel'
HELP_FRASE = "Send a randomly phrase, there's a chance of getting the braba"
HELP_HELP = 'This command :)'
ABSOLUTE_PATH = '' ABSOLUTE_PATH = ''
COOKIE_PATH = '/config/cookies/cookies.txt' COOKIE_PATH = '/config/cookies/cookies.txt'
@ -39,3 +62,14 @@ COLOURS = {
'grey': 0x708090, 'grey': 0x708090,
'blue': 0x3498DB 'blue': 0x3498DB
} }
MEMBERS_MAXIMUM_DROPS = {
'RafaelV': 1,
'Gassu': 2,
'LopesZ3R4': 4,
'BABIGIRL': 4,
'Hijãomi': 2,
'Jillian': 4,
'Maxymuns': 2
}

View File

@ -22,7 +22,7 @@ if __name__ == '__main__':
print("Error: No bot token!") print("Error: No bot token!")
exit() exit()
bot.log_error = ErrorHandler('errors') # Creating the error handler bot.log_error = ErrorHandler('errors')
for extension in config.INITIAL_EXTENSIONS: for extension in config.INITIAL_EXTENSIONS:
try: try:

5
teste.py Normal file
View File

@ -0,0 +1,5 @@
x = {
'rafael': 5
}
print(x['Tteste'])

View File

@ -8,8 +8,8 @@ MAXIMUM_TRIES = 10
class ErrorHandler(): class ErrorHandler():
"""Receive errors to write into a log file """Receive errors to write into a log file
Arg: Arg:
folder_path = Relative path from root to where the logs should be create folder_path = Relative path from root to where the logs should be create
""" """
def __init__(self, folder_path='') -> None: def __init__(self, folder_path='') -> None:

View File

@ -1,3 +1,4 @@
from discord.client import Client
import requests import requests
import json import json
from config import config from config import config
@ -8,20 +9,12 @@ from random import random as rand
class Phrases(commands.Cog): class Phrases(commands.Cog):
"""Deal with the generation of motivational phrases""" """Deal with the generation of motivational phrases"""
def __init__(self, bot): def __init__(self, bot: Client):
self.__bot = bot self.__bot = bot
@property @commands.command(name='frase', help=config.HELP_FRASE)
def bot(self):
return self.__bot
@bot.setter
def bot(self, newBot):
self.__bot = newBot
@commands.command(name='frase', help='Envia uma frase pica, talvez a braba')
async def phrase(self, ctx): async def phrase(self, ctx):
# There is a chance that the phrase will be send for the dev """Send some phrase to the requester"""
secret = await self.__calculate_rgn() secret = await self.__calculate_rgn()
if secret != None: if secret != None:
await ctx.send(secret) await ctx.send(secret)
@ -30,6 +23,7 @@ class Phrases(commands.Cog):
await ctx.send(phrase) await ctx.send(phrase)
async def __calculate_rgn(self): async def __calculate_rgn(self):
"""Calculate the chance from the phrase function return a secret custom message"""
x = rand() x = rand()
if x < 0.15: if x < 0.15:
return config.SECRET_MESSAGE return config.SECRET_MESSAGE
@ -37,6 +31,7 @@ class Phrases(commands.Cog):
return None return None
async def __get_phrase(self): async def __get_phrase(self):
"""Get the phrase from the server"""
tries = 0 tries = 0
while True: while True:
tries += 1 tries += 1
@ -50,7 +45,7 @@ class Phrases(commands.Cog):
phrase = data['quoteText'] phrase = data['quoteText']
author = data['quoteAuthor'] author = data['quoteAuthor']
if phrase == '' or author == '': # Don't accept incomplete phrases if phrase == '' or author == '':
continue continue
text = f'{phrase} \nBy: {author}' text = f'{phrase} \nBy: {author}'

View File

@ -3,14 +3,13 @@ import discord
from discord.ext import commands from discord.ext import commands
from config import config from config import config
class Random(commands.Cog): class Random(commands.Cog):
"""Deal with returning random things""" """Deal with returning random things"""
def __init__(self, bot): def __init__(self, bot):
self.__bot = bot self.__bot = bot
@commands.command(name='random', help='Número aleatório de 1 a X') @commands.command(name='random', help=config.HELP_RANDOM)
async def random(self, ctx, arg: str): async def random(self, ctx, arg: str):
try: try:
arg = int(arg) arg = int(arg)
@ -38,7 +37,7 @@ class Random(commands.Cog):
) )
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name='cara', help='coroa') @commands.command(name='cara', help=config.HELP_CARA)
async def cara(self, ctx): async def cara(self, ctx):
x = random() x = random()
if x < 0.5: if x < 0.5:
@ -53,7 +52,7 @@ class Random(commands.Cog):
) )
await ctx.send(embed=embed) await ctx.send(embed=embed)
@commands.command(name='escolha', help='Escolhe um dos itens, separador: Vírgula') @commands.command(name='escolha', help=config.HELP_ESCOLHA)
async def escolher(self, ctx, *args: str): async def escolher(self, ctx, *args: str):
try: try:
user_input = " ".join(args) user_input = " ".join(args)

View File

@ -13,13 +13,14 @@ class Warframe(commands.Cog):
self.__bot = bot self.__bot = bot
self.__open_functions = ['cetus', 'cambion', 'fissures'] self.__open_functions = ['cetus', 'cambion', 'fissures']
@commands.command(name='warframe', help='<x> - Retorna informações de x') @commands.command(name='warframe', help=config.HELP_WARFRAME)
async def warframe(self, ctx, arg): async def warframe(self, ctx, arg) -> Embed:
if arg in self.__open_functions: if arg in self.__open_functions:
function = getattr(Warframe, f'_Warframe__{arg}') # Get the required function # Get the required function
embed = await function(self) # Execute the function passing self function = getattr(Warframe, f'_Warframe__{arg}')
embed = await function(self) # Execute the function passing self
await ctx.send(embed=embed) # Return the result await ctx.send(embed=embed) # Return the result
else: else:
info = f'Warframe commands: {self.__open_functions}' info = f'Warframe commands: {self.__open_functions}'
@ -39,7 +40,7 @@ class Warframe(commands.Cog):
) )
return embed return embed
async def __get_cetus(self): async def __get_cetus(self) -> str:
"""Return the information of the Warframe API""" """Return the information of the Warframe API"""
tries = 0 tries = 0
while True: while True:
@ -66,7 +67,7 @@ class Warframe(commands.Cog):
) )
return embed return embed
async def __get_cambion(self): async def __get_cambion(self) -> str:
"""Return the information of the Warframe API""" """Return the information of the Warframe API"""
tries = 0 tries = 0
while True: while True:
@ -94,7 +95,7 @@ class Warframe(commands.Cog):
) )
return embed return embed
async def __get_fissures(self): async def __get_fissures(self) -> str:
"""Return the information of the Warframe API""" """Return the information of the Warframe API"""
tries = 0 tries = 0
while True: while True:

View File

@ -0,0 +1,51 @@
from discord.ext import commands
from discord import Member, Client
from config import config
class Admin(commands.Cog):
"""Deal with administration of users in server"""
def __init__(self, bot: Client):
self.__bot = bot
@commands.command(name='drop', help='Manda um membro para a Terapia')
async def drop(self, ctx, name):
user: Member = None
guild = ctx.guild
for member in guild.members:
if member.name == name:
user = member
break
if user == None:
await ctx.send(f'{name} não foi encontrado, utilize o nome de usuário ao invés do apelido do servidor')
return
permanent_drops = False
maximum_drops = None
try:
maximum_drops = config.MEMBERS_MAXIMUM_DROPS[user.name]
except KeyError:
permanent_drops = True
except Exception as e:
await ctx.send('Houve algum erro :/')
return
if maximum_drops == 0:
await ctx.send(f'{user.name} já foi dropado várias vezes, larga o cara bicho')
return
if user.voice == None:
await ctx.send(f'{user.name} precisa estar conectado a um canal de voz antes')
else:
await user.move_to(None) # Remove from voice
if not permanent_drops:
# Att the life of user
config.MEMBERS_MAXIMUM_DROPS[user.name] -= 1
def setup(bot):
bot.add_cog(Admin(bot))

View File

@ -1,4 +1,5 @@
import discord import discord
from discord import Client
from discord.ext.commands.errors import CommandNotFound, MissingRequiredArgument from discord.ext.commands.errors import CommandNotFound, MissingRequiredArgument
from discord.ext import commands from discord.ext import commands
from config import config from config import config
@ -7,24 +8,16 @@ from config import config
class Control(commands.Cog): class Control(commands.Cog):
"""Control the flow of the Bot""" """Control the flow of the Bot"""
def __init__(self, bot): def __init__(self, bot: Client):
self.__bot = bot self.__bot = bot
self.__comandos = { self.__comandos = {
'MUSIC': ['resume', 'pause', 'loop', 'stop', 'skip', 'play', 'queue', 'clear', 'np', 'shuffle', 'move'], 'MUSIC': ['resume', 'pause', 'loop', 'stop', 'skip', 'play', 'queue', 'clear', 'np', 'shuffle', 'move'],
'WARFRAME': ['warframe'], 'WARFRAME': ['warframe'],
'RANDOM': ['escolha', 'cara', 'random'], 'RANDOM': ['escolha', 'cara', 'random'],
'HELP': ['help'], 'HELP': ['help'],
'OTHERS': ['frase'] 'OTHERS': ['frase', 'drop']
} }
@property
def bot(self):
return self.__bot
@bot.setter
def bot(self, newBot):
self.__bot = newBot
@commands.Cog.listener() @commands.Cog.listener()
async def on_ready(self): async def on_ready(self):
print(config.STARTUP_MESSAGE) print(config.STARTUP_MESSAGE)
@ -38,9 +31,10 @@ class Control(commands.Cog):
elif isinstance(error, CommandNotFound): elif isinstance(error, CommandNotFound):
await ctx.channel.send(f'O comando não existe') await ctx.channel.send(f'O comando não existe')
else: else:
await ctx.channel.send(f'Teve um erro aí bicho')
raise error raise error
@commands.command(name="help", alisases=['ajuda'], help="Comando de ajuda") @commands.command(name="help", alisases=['ajuda'], help=config.HELP_HELP)
async def help_msg(self, ctx): async def help_msg(self, ctx):
helptxt = '' helptxt = ''
help_music = '-- MUSIC\n' help_music = '-- MUSIC\n'

View File

@ -1,20 +1,13 @@
from discord import Client
from discord.ext import commands from discord.ext import commands
class Filter(commands.Cog): class Filter(commands.Cog):
"""Deal with filtering of discord messages""" """Deal with filtering of discord messages"""
def __init__(self, bot): def __init__(self, bot: Client):
self.__bot = bot self.__bot = bot
@property
def bot(self):
return self.__bot
@bot.setter
def bot(self, newBot):
self.__bot = newBot
@commands.Cog.listener() @commands.Cog.listener()
async def on_message(self, message): async def on_message(self, message):
if message.author == self.__bot.user: if message.author == self.__bot.user:

View File

@ -8,6 +8,7 @@ from yt_dlp.utils import ExtractorError, DownloadError
from vulkanbot.music.Song import Song from vulkanbot.music.Song import Song
from vulkanbot.music.utils import is_url from vulkanbot.music.utils import is_url
class Downloader(): class Downloader():
"""Download musics direct URL and title or Source from Youtube using a music name or Youtube URL""" """Download musics direct URL and title or Source from Youtube using a music name or Youtube URL"""
@ -25,13 +26,13 @@ class Downloader():
print('Invalid song identifier type') print('Invalid song identifier type')
return return
if is_url(song.identifier): # Youtube URL if is_url(song.identifier): # Youtube URL
song_info = self.__download_url(song.identifier) song_info = self.__download_url(song.identifier)
else: # Song name else: # Song name
song_info = self.__download_title(song.identifier) song_info = self.__download_title(song.identifier)
if song_info == None: if song_info == None:
song.destroy() # Destroy the music with problems song.destroy() # Destroy the music with problems
return None return None
else: else:
song.finish_down(song_info) song.finish_down(song_info)
@ -54,7 +55,8 @@ class Downloader():
if result.get('entries'): # If got a dict of musics if result.get('entries'): # If got a dict of musics
for entry in result['entries']: for entry in result['entries']:
songs_identifiers.append(f"https://www.youtube.com/watch?v={entry['id']}") songs_identifiers.append(
f"https://www.youtube.com/watch?v={entry['id']}")
else: # Or a single music else: # Or a single music
songs_identifiers.append(result['original_url']) songs_identifiers.append(result['original_url'])
@ -89,18 +91,19 @@ class Downloader():
except (ExtractorError, DownloadError) as e: # Any type of error in download except (ExtractorError, DownloadError) as e: # Any type of error in download
print(e) print(e)
async def __download_songs(self, song: Song): async def __download_songs(self, song: Song) -> None:
if song.source != None: # If Music already preloaded """Download a music object asynchronously"""
if song.source != None: # If Music already preloaded
return return
def download_song(song): def download_song(song):
if is_url(song.identifier): # Youtube URL if is_url(song.identifier): # Youtube URL
song_info = self.__download_url(song.identifier) song_info = self.__download_url(song.identifier)
else: # Song name else: # Song name
song_info = self.__download_title(song.identifier) song_info = self.__download_title(song.identifier)
if song_info == None: if song_info == None:
song.destroy() # Remove the song with problems from the playlist song.destroy() # Remove the song with problems from the playlist
else: else:
song.finish_down(song_info) song.finish_down(song_info)
@ -110,7 +113,7 @@ class Downloader():
max_workers=config.MAX_PRELOAD_SONGS max_workers=config.MAX_PRELOAD_SONGS
) )
await asyncio.wait(fs={loop.run_in_executor(executor, download_song, song)}, await asyncio.wait(fs={loop.run_in_executor(executor, download_song, song)},
return_when=asyncio.ALL_COMPLETED) return_when=asyncio.ALL_COMPLETED)
def __download_title(self, title: str) -> dict: def __download_title(self, title: str) -> dict:
"""Download a music full information using his name. """Download a music full information using his name.

View File

@ -4,7 +4,6 @@ from abc import ABC, abstractproperty, abstractmethod
class IPlaylist(ABC): class IPlaylist(ABC):
"""Class to manage and control the songs to play and played""" """Class to manage and control the songs to play and played"""
@abstractproperty @abstractproperty
def looping_one(self): def looping_one(self):
pass pass
@ -75,7 +74,7 @@ class ISong(ABC):
@abstractmethod @abstractmethod
def title(self) -> str: def title(self) -> str:
pass pass
@abstractmethod @abstractmethod
def duration(self) -> str: def duration(self) -> str:
@ -88,4 +87,3 @@ class ISong(ABC):
@abstractmethod @abstractmethod
def destroy(self) -> None: def destroy(self) -> None:
pass pass

View File

@ -17,12 +17,12 @@ class Music(commands.Cog):
self.__bot: discord.Client = bot self.__bot: discord.Client = bot
self.__playing = False self.__playing = False
self.__ffmpeg = 'C:/ffmpeg/bin/ffmpeg.exe' self.__vc = ""
self.__vc = "" # Objeto voice_bot 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': config.FFMPEG_PATH,
'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 __play_next(self, error, ctx): def __play_next(self, error, ctx):
while True: while True:
@ -49,7 +49,7 @@ class Music(commands.Cog):
songs = self.__playlist.songs_to_preload songs = self.__playlist.songs_to_preload
await self.__downloader.preload(songs) await self.__downloader.preload(songs)
@commands.command(name="play", help="Toca música - YouTube/Spotify/Título", aliases=['p', 'tocar']) @commands.command(name="play", help=config.HELP_PLAY, aliases=['p', 'tocar'])
async def play(self, ctx, *args): async def play(self, ctx, *args):
user_input = " ".join(args) user_input = " ".join(args)
@ -65,31 +65,33 @@ class Music(commands.Cog):
songs_quant = 0 songs_quant = 0
musics_identifiers, provider = self.__searcher.search(user_input) musics_identifiers, provider = self.__searcher.search(user_input)
if provider == Provider.Unknown: # If type not identified if provider == Provider.Unknown: # If type not identified
await self.__send_embed(ctx, description='Entrada inválida, tente algo melhor', colour_name='blue') await self.__send_embed(ctx, description='Entrada inválida, tente algo melhor', colour_name='blue')
return return
if provider == Provider.YouTube: # If youtube source if provider == Provider.YouTube: # If youtube source
musics_identifiers = self.__downloader.extract_youtube_link(musics_identifiers[0]) musics_identifiers = self.__downloader.extract_youtube_link(
musics_identifiers[0])
for identifier in musics_identifiers: # Creating songs for identifier in musics_identifiers: # Creating songs
last_song = self.__playlist.add_song(identifier) last_song = self.__playlist.add_song(identifier)
songs_quant += 1 songs_quant += 1
songs_preload = self.__playlist.songs_to_preload songs_preload = self.__playlist.songs_to_preload
await self.__downloader.preload(songs_preload) await self.__downloader.preload(songs_preload)
if songs_quant == 1: # If only one music downloaded if songs_quant == 1: # If only one music downloaded
song = self.__downloader.download_one(last_song) # Download the new music song = self.__downloader.download_one(
last_song) # Download the new music
if song == None: # If song not downloaded if song == None: # If song not downloaded
await self.__send_embed(ctx, description='Houve um problema no download dessa música, tente novamente', colour_name='blue') await self.__send_embed(ctx, description='Houve um problema no download dessa música, tente novamente', colour_name='blue')
elif not self.__playing : # If not playing elif not self.__playing: # If not playing
await self.__send_embed(ctx, description=f'Você adicionou a música **{song.title}** à playlist', colour_name='blue') await self.__send_embed(ctx, description=f'Você adicionou a música **{song.title}** à playlist', colour_name='blue')
else: # If playing else: # If playing
await ctx.send(embed=song.embed(title='Song added to Queue')) await ctx.send(embed=song.embed(title='Song added to Queue'))
else: else:
await self.__send_embed(ctx, description=f"Você adicionou {songs_quant} músicas à fila!", colour_name='blue') await self.__send_embed(ctx, description=f"Você adicionou {songs_quant} músicas à fila!", colour_name='blue')
@ -104,20 +106,20 @@ class Music(commands.Cog):
break break
while True: while True:
if first.source != None: # If song got downloaded if first.source != None: # If song got downloaded
try_another = False try_another = False
break break
if first.problematic: # If song got any error, try another one if first.problematic: # If song got any error, try another one
break break
else: # The song is downloading, checking another time else: # The song is downloading, checking another time
continue continue
if first != None: if first != None:
await self.__play_music(ctx, first) await self.__play_music(ctx, first)
@commands.command(name="queue", help="Mostra as atuais músicas da fila.", aliases=['q', 'fila']) @commands.command(name="queue", help=config.HELP_QUEUE, aliases=['q', 'fila'])
async def queue(self, ctx): async def queue(self, ctx):
if self.__playlist.looping_one: # If Repeating one if self.__playlist.looping_one: # If Repeating one
await self.now_playing(ctx) await self.now_playing(ctx)
@ -125,7 +127,8 @@ class Music(commands.Cog):
songs_preload = self.__playlist.songs_to_preload songs_preload = self.__playlist.songs_to_preload
await self.__downloader.preload(songs_preload) await self.__downloader.preload(songs_preload)
total_time = format_time(sum([int(song.duration if song.duration else 0) for song in songs_preload])) # Sum the duration total_time = format_time(sum([int(song.duration if song.duration else 0)
for song in songs_preload])) # Sum the duration
total_songs = len(self.__playlist) total_songs = len(self.__playlist)
text = f'Total musics: {total_songs} | Duration: `{total_time}` downloaded \n\n' text = f'Total musics: {total_songs} | Duration: `{total_time}` downloaded \n\n'
@ -141,12 +144,12 @@ class Music(commands.Cog):
else: # No music else: # No music
await self.__send_embed(ctx, description='There is not musics in queue.', 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=config.HELP_SKIP, aliases=['pular'])
async def skip(self, ctx): async def skip(self, ctx):
if len(self.__bot.voice_clients) > 0: if len(self.__bot.voice_clients) > 0:
self.__vc.stop() self.__vc.stop()
@commands.command(name='stop', help='Para de tocar músicas') @commands.command(name='stop', help=config.HELP_STOP)
async def stop(self, ctx): async def stop(self, ctx):
if self.__vc == '': if self.__vc == '':
return return
@ -155,7 +158,7 @@ class Music(commands.Cog):
self.__vc.stop() self.__vc.stop()
await self.__vc.disconnect() await self.__vc.disconnect()
@commands.command(name='pause', help='Pausa a música') @commands.command(name='pause', help=config.HELP_PAUSE)
async def pause(self, ctx): async def pause(self, ctx):
if self.__vc == '': if self.__vc == '':
return return
@ -163,7 +166,7 @@ class Music(commands.Cog):
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='Solta a música atual') @commands.command(name='resume', help=config.HELP_RESUME)
async def resume(self, ctx): async def resume(self, ctx):
if self.__vc == '': if self.__vc == '':
return return
@ -171,7 +174,7 @@ class Music(commands.Cog):
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='loop', help='Controla a repetição de músicas') @commands.command(name='loop', help=config.HELP_LOOP)
async def loop(self, ctx, args: str): async def loop(self, ctx, args: str):
args = args.lower() args = args.lower()
if args == 'one': if args == 'one':
@ -185,11 +188,11 @@ class Music(commands.Cog):
await self.__send_embed(ctx, description=description, colour_name='grey') await self.__send_embed(ctx, description=description, colour_name='grey')
@commands.command(name='clear', help='Limpa a fila de músicas a tocar') @commands.command(name='clear', help=config.HELP_CLEAR)
async def clear(self, ctx): async def clear(self, ctx):
self.__playlist.clear() self.__playlist.clear()
@commands.command(name='np', help='Mostra a música que está tocando no instante') @commands.command(name='np', help=config.HELP_NP)
async def now_playing(self, ctx): async def now_playing(self, ctx):
if self.__playlist.looping_one: if self.__playlist.looping_one:
title = 'Song Looping Now' title = 'Song Looping Now'
@ -199,20 +202,7 @@ class Music(commands.Cog):
current_song = self.__playlist.current current_song = self.__playlist.current
await ctx.send(embed=current_song.embed(title=title)) await ctx.send(embed=current_song.embed(title=title))
async def __send_embed(self, ctx, title='', description='', colour_name='grey'): @commands.command(name='shuffle', help=config.HELP_SHUFFLE)
try:
colour = config.COLOURS[colour_name]
except Exception as e:
colour = config.COLOURS['grey']
embedvc = discord.Embed(
title=title,
description=description,
colour=colour
)
await ctx.send(embed=embedvc)
@commands.command(name='shuffle', help='Altera aleatoriamente a ordem das músicas')
async def shuffle(self, ctx): async def shuffle(self, ctx):
self.__playlist.shuffle() self.__playlist.shuffle()
songs = self.__playlist.songs_to_preload songs = self.__playlist.songs_to_preload
@ -221,7 +211,7 @@ class Music(commands.Cog):
await self.__send_embed(ctx, description='Musicas embaralhadas', colour_name='blue') await self.__send_embed(ctx, description='Musicas embaralhadas', colour_name='blue')
@commands.command(name='move', help='Manda uma música de uma posição para outra <from> <to>') @commands.command(name='move', help=config.HELP_MOVE)
async def move(self, ctx, pos1, pos2='1'): async def move(self, ctx, pos1, pos2='1'):
try: try:
pos1 = int(pos1) pos1 = int(pos1)
@ -241,5 +231,19 @@ class Music(commands.Cog):
else: else:
await ctx.send(reason) await ctx.send(reason)
async def __send_embed(self, ctx, title='', description='', colour_name='grey'):
try:
colour = config.COLOURS[colour_name]
except Exception as e:
colour = config.COLOURS['grey']
embedvc = discord.Embed(
title=title,
description=description,
colour=colour
)
await ctx.send(embed=embedvc)
def setup(bot): def setup(bot):
bot.add_cog(Music(bot)) bot.add_cog(Music(bot))

View File

@ -1,12 +1,11 @@
from collections import deque from collections import deque
import random
from config import config from config import config
import random
from vulkanbot.music.Interfaces import IPlaylist from vulkanbot.music.Interfaces import IPlaylist
from vulkanbot.music.Song import Song from vulkanbot.music.Song import Song
class Playlist(IPlaylist): class Playlist(IPlaylist):
"""Class to manage and control the songs to play and played""" """Class to manage and control the songs to play and played"""
@ -21,23 +20,23 @@ class Playlist(IPlaylist):
self.__current: Song = None self.__current: Song = None
@property @property
def looping_one(self): def looping_one(self) -> bool:
return self.__looping_one return self.__looping_one
@property @property
def looping_all(self): def looping_all(self) -> bool:
return self.__looping_all return self.__looping_all
@property @property
def current(self): def current(self) -> Song:
return self.__current return self.__current
@property @property
def songs_to_preload(self) -> list: def songs_to_preload(self) -> list:
return list(self.__queue)[:config.MAX_PRELOAD_SONGS] return list(self.__queue)[:config.MAX_PRELOAD_SONGS]
def __len__(self): def __len__(self) -> int:
return len(self.__queue) return len(self.__queue)
def next_song(self) -> Song: def next_song(self) -> Song:
"""Return the next song to play""" """Return the next song to play"""
@ -59,14 +58,16 @@ class Playlist(IPlaylist):
if len(self.__queue) == 0: # If no more song to play, return None if len(self.__queue) == 0: # If no more song to play, return None
return None return None
self.__current = self.__queue[0] # Att the current with the first one # Att the current with the first one
self.__current = self.__queue[0]
self.__queue.popleft() # Remove the current from queue self.__queue.popleft() # Remove the current from queue
self.__name_history.append(self.__current.identifier) # Add to name history self.__name_history.append(
self.__current.identifier) # Add to name history
self.__songs_history.append(self.__current) # Add to song history self.__songs_history.append(self.__current) # Add to song history
return self.__current return self.__current
def prev_song(self): def prev_song(self) -> Song:
"""Return the source of the last song played """Return the source of the last song played
Return None or the source of the prev song Return None or the source of the prev song
@ -143,7 +144,7 @@ class Playlist(IPlaylist):
Positions: First music is 1 Positions: First music is 1
Return (Error bool, string) with the status of the function, to show to user Return (Error bool, string) with the status of the function, to show to user
""" """
if pos2 not in range(1, len(self.__queue)) or pos1 not in range(1, len(self.__queue)): if pos2 not in range(1, len(self.__queue) + 1) or pos1 not in range(1, len(self.__queue) + 1):
return (False, 'Numbers need to be more than 0 and less than the queue length') return (False, 'Numbers need to be more than 0 and less than the queue length')
try: try:

View File

@ -44,4 +44,3 @@ class Searcher():
# If no match # If no match
return Provider.Unknown return Provider.Unknown

View File

@ -1,7 +1,8 @@
from discord import Embed from discord import Embed
import datetime
from vulkanbot.music.Interfaces import ISong, IPlaylist
from config import config from config import config
import datetime
from vulkanbot.music.Interfaces import ISong, IPlaylist
class Song(ISong): class Song(ISong):

View File

@ -1,33 +1,6 @@
import spotipy import spotipy
import re
from spotipy.oauth2 import SpotifyClientCredentials from spotipy.oauth2 import SpotifyClientCredentials
from bs4 import BeautifulSoup
from config import config from config import config
import aiohttp
class Browser():
def __init__(self) -> None:
self.__url_regex = re.compile(
"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+")
self.__session = aiohttp.ClientSession(
headers={'User-Agent': 'python-requests/2.20.0'})
async def search(self, url) -> str:
"""Convert the external_url link to the title of music using browser"""
if re.search(self.__url_regex, url):
result = self.__url_regex.search(url)
url = result.group(0)
async with self.__session.get(url) as response:
page = await response.text()
soup = BeautifulSoup(page, 'html.parser')
title = soup.find('title')
title = title.string
title = title.replace('- song by', '')
title = title.replace('| Spotify', '')
return title
class SpotifySearch(): class SpotifySearch():
@ -35,7 +8,6 @@ class SpotifySearch():
def __init__(self) -> None: def __init__(self) -> None:
self.__connected = False self.__connected = False
self.__browser = Browser()
def connect(self) -> bool: def connect(self) -> bool:
try: try:
@ -142,8 +114,3 @@ class SpotifySearch():
title += f'{artist["name"]} ' title += f'{artist["name"]} '
return title return title
async def __convert_spotify(self, url) -> str:
"""(Experimental) - Convert the external_url link to the title of music using browser"""
title = self.__browser(url)
return title

View File

@ -1,5 +1,6 @@
import re import re
def format_time(duration): def format_time(duration):
if not duration: if not duration:
return "00:00" return "00:00"