mirror of
https://github.com/RafaelSolVargas/Vulkan.git
synced 2025-10-29 16:57:23 +00:00
Merge pull request #6 from RafaelSolVargas/fixing-spotify-bug
Adding new Adming Module and Stylish update
This commit is contained in:
commit
aa4bb00745
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
2
main.py
2
main.py
@ -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:
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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}'
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
51
vulkanbot/general/Admin.py
Normal file
51
vulkanbot/general/Admin.py
Normal 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))
|
||||||
@ -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'
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -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:
|
||||||
|
|||||||
@ -44,4 +44,3 @@ class Searcher():
|
|||||||
|
|
||||||
# If no match
|
# If no match
|
||||||
return Provider.Unknown
|
return Provider.Unknown
|
||||||
|
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -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
|
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user