premier commit

This commit is contained in:
Mylloon 2020-11-29 11:39:41 +01:00
commit 15716f8ea9
9 changed files with 1500 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
UPDATE/
.dockerignore
Dockerfile
setup.py
cogs/music_old.py

108
cogs/fun.py Normal file
View file

@ -0,0 +1,108 @@
import discord
from discord.ext import commands
from random import randint, choice
def setup(client):
client.add_cog(Fun(client))
class Fun(commands.Cog):
"""Commandes plutôt fun."""
def __init__(self, client):
self.client = client
@commands.command(name='iq')
async def _iq(self, ctx, *, user = '0'):
"""Calcule ton IQ.\n ➡ Syntaxe: .iq [user]"""
if user == '0':
user = ctx.author
await ctx.message.add_reaction(emoji = '')
return await ctx.send(f"T'as {randint(randint(-100,0),220)} IQ {user.mention} !")
else:
try:
user2 = user
user2 = user2[2:-1]
user2 = user2.replace("!","")
user2 = int(user2)
user2 = self.client.get_user(user2)
KassouBot = self.client.get_user(740140888373854269)
if user2.id == KassouBot.id:
await ctx.message.add_reaction(emoji = '')
return await ctx.send(f"Bah... pas ouf... j'ai juste 100000 IQ :/")
else:
await ctx.message.add_reaction(emoji = '')
message = await ctx.send("...")
return await message.edit(content = f"{user2.mention} a {randint(randint(-100,0),220)} IQ !")
except:
await ctx.message.add_reaction(emoji = '')
message = await ctx.send("...")
return await message.edit(content = f"{user} a {randint(randint(-100,0),220)} IQ !")
@commands.command(name='love')
async def _love(self, ctx, *users: discord.Member):
"""Découvre la probabilité que ces deux personnes se mettent en couple.\n ➡ Syntaxe: .love <User1> <User2>"""
if len(users) == 2 or len(users) == 1:
UneDemande = False
if len(users) == 1:
U = users
users = []
users.append(U[0])
users.append(ctx.author)
UneDemande = True
if users[0] == users[1]:
await ctx.message.add_reaction(emoji = '')
return await ctx.send("Je suis sûr que cette personne s'aime ! :angry:")
if users[0].nick:
user1 = list(users[0].nick)
else:
user1 = list(users[0].name)
if users[1].nick:
user2 = list(users[1].nick)
else:
user2 = list(users[1].name)
user1_CALC = self._retirerDoublons([x.lower() for x in user1])
user2_CALC = self._retirerDoublons([x.lower() for x in user2])
coef_amour = 0
if len(user1_CALC) > len(user2_CALC):
taille_du_pls_grand = len(user1_CALC)
taille_du_ms_grand = len(user2_CALC)
else:
taille_du_pls_grand = len(user2_CALC)
taille_du_ms_grand = len(user1_CALC)
coef_amour = round(float(len(list(set(user1_CALC).intersection(user2_CALC))) / taille_du_pls_grand),1) * 100 + ((taille_du_pls_grand-taille_du_ms_grand) * 1.5) * 1.7
if coef_amour > 100:
coef_amour = 100
if UneDemande == True:
await ctx.message.add_reaction(emoji = '')
return await ctx.send(f"Tu as {coef_amour}% de chance de te mettre en couple avec {''.join(user1)}")
await ctx.message.add_reaction(emoji = '')
await ctx.send(f"{''.join(user1)} et {''.join(user2)} ont {coef_amour}% de chance de se mettre en couple !")
else:
await ctx.message.add_reaction(emoji = '')
await ctx.send("Erreur! Syntaxe : `.love <User1> [User2]`\n")
def _retirerDoublons(self, liste):
Newliste = []
for element in liste:
if element not in Newliste:
Newliste.append(element)
return Newliste
@_love.error
async def _love_error(self, ctx, error):
await ctx.send(str(error).replace('Member "', "Le membre **").replace('" not found', "** n'as pas été trouvé."))
@commands.command(name='8ball', aliases=['8b', '8balls'])
async def _8ball(self, ctx, *, question):
"""Répond à ta question 🔮.\n ➡ Syntaxe: .8ball/8b <question>"""
reponses=["c'est sûr.","il en est décidément ainsi.","incontestablement.","oui sans aucun doute.","tu peux t'y fier.","tel que je le vois, oui.","c'est le plus probable.",
"cela montre de bonnes perspectives.","certes.","les signes indiquent que oui.","ma réponse est oui.","ta question est trop floue, réessaie.","redemandes plus tard stp.",
"je ferais mieux de pas te le dire maintenant...","je ne peux pas le prédire actuellement :/","concentre-toi et redemande.","n'y comptes pas trop.","ma réponse est non.",
"mes sources disent que non.", "les perspectives ne sont pas si bonnes...","c'est très douteux."]
await ctx.send(f"{ctx.author.mention}, {choice(reponses)}")
@_8ball.error
async def _8ball_error(self, ctx, error):
if str(error) == "question is a required argument that is missing.":
await ctx.send("Mauvaise syntaxe : `.8ball/8b/8balls <question>`.")
@commands.command(name='pileouface', aliases=['pf'])
async def _pileouface(self, ctx):
return await ctx.send(f"{'Pile' if randint(0,1) == 1 else 'Face'} !")

93
cogs/games.py Normal file
View file

@ -0,0 +1,93 @@
import discord
from discord.ext import commands
from random import randint, choice
import asyncio
def setup(client):
client.add_cog(Games(client))
class Games(commands.Cog):
"""Commandes relatives aux jeux."""
def __init__(self, client):
self.client = client
self.guessing_game = {}
@commands.command(name='chifumi', aliases = ["shifumi", "ppc"])
async def _chifumi(self, ctx, *, choix):
"""Un simple Chifumi contre le bot.\n ➡ Syntaxe: .chifumi/shifumi/ppc <pierre/papier/ciseaux>"""
choix_jeu = ["Pierre ✊", "Papier 🧻", "Ciseaux ✂"]
orditxt = choice(choix_jeu)
ordi = choix_jeu.index(orditxt)
PIERRE = 0
PAPIER = 1
CISEAUX = 2
choix = choix.lower()
if choix == "pierre":
choix = PIERRE
if choix == "papier" or choix == "feuille":
choix = PAPIER
if choix == "ciseaux" or choix == "ciseau":
choix = CISEAUX
description = (f"{choix_jeu[choix][:-1]} VS {choix_jeu[ordi][:-1]}\n\n**"
f"{('Égalité !', 'Tu as perdu !', 'Tu as gagné !')[(choix != ordi) + ((choix > ordi and ordi +1 == choix) or (choix < ordi and choix + ordi == 2))]}**")
embed = discord.Embed(title = f"{choix_jeu[choix][-1:]}VS {choix_jeu[ordi][-1:]}", description = description)
embed.set_author(name = ctx.author.name, icon_url = ctx.author.avatar_url)
await ctx.send(embed = embed)
await ctx.message.add_reaction(emoji = '')
@_chifumi.error
async def _chifumi_error(self, ctx, error):
await ctx.send("Mauvaise syntaxe : `.chifumi/shifumi/ppc <pierre/papier/ciseaux>`.")
@commands.command(name='plusoumoins', aliases = ['+ou-', '+-'])
async def _plusoumoins(self, ctx):
"""Un plus ou moins entre 1 et 100.\n ➡ Syntaxe: .plusoumoins/+ou-/+-"""
if str(ctx.author.id) in self.guessing_game:
return await ctx.send("Tu es déjà en partie.")
guess = 5
self.guessing_game[str(ctx.author.id)] = guess
number = randint(1,100)
message = f"Choisis un nombre entre 1 et 100 {ctx.author.mention}."
await ctx.send(message)
while self.guessing_game[str(ctx.author.id)] != 0:
try:
def check(message):
if message.author.bot == False:
return str(message.author.id) in self.guessing_game
msg = await self.client.wait_for('message', check = check, timeout = 30)
except asyncio.TimeoutError:
del self.guessing_game[str(ctx.author.id)]
return await ctx.send(f"Tu as mis trop de temps a répondre {ctx.author.mention}. La réponse était {number}.")
if msg.author == ctx.author:
if msg.content == "stop":
del self.guessing_game[str(ctx.author.id)]
return await ctx.send(f"Fin du plus ou moins {ctx.author.mention}. La réponse était {number}.")
try:
attempt = int(msg.content)
if attempt > number:
if guess-1 != 0:
await ctx.send(f"J'pense que c'est moins {ctx.author.mention}... Il te reste {guess-1} essai{'s' if guess-1>1 else ''}.")
guess -= 1
self.guessing_game[str(ctx.author.id)] = guess
if guess != 0:
await ctx.send(message)
elif attempt < number:
if guess-1 != 0:
await ctx.send(f"J'pense que c'est plus {ctx.author.mention}... Il te reste {guess-1} essai{'s' if guess-1>1 else ''}.")
guess -=1
self.guessing_game[str(ctx.author.id)] = guess
if guess != 0:
await ctx.send(message)
elif attempt == number:
del self.guessing_game[str(ctx.author.id)]
return await ctx.send(f"Tu as trouvé {ctx.author.mention}, bien joué !")
except:
await ctx.send(f"Erreur dans la réponse {ctx.author.mention}, merci de n'écrire qu'un nombre. Tapez `stop` pour arrêter le jeu.")
del self.guessing_game[str(ctx.author.id)]
await ctx.send(f"T'as pas trouvé {ctx.author.mention}... dommage, c'était {number}.")

67
cogs/help.py Normal file
View file

@ -0,0 +1,67 @@
import discord
from discord.ext import commands
from random import randint
def setup(client):
client.add_cog(Help(client))
class Help(commands.Cog):
"""Listes des commandes et/ou catégories."""
def __init__(self, client):
self.client = client
self.client.remove_command("help")
@commands.command(name='help')
async def _help(self, ctx, *cog):
"""Affiche toutes les commandes du bot.\n ➡ Syntaxe: .help [catégorie]"""
if not cog:
"""Liste des Cog"""
halp=discord.Embed(title = 'Liste des catégories et commandes sans catégorie',
description = f'Utilisez `{ctx.prefix}help [catégorie]` pour en savoir plus sur elles et leur commande.',
color = randint(0, 0xFFFFFF))
for name_cog in self.client.cogs:
liste_cmds = ""
nb_cmds = 0
for cmds in self.client.get_cog(name_cog).get_commands():
if not cmds.hidden:
liste_cmds += f", `{ctx.prefix}{cmds.name}`"
nb_cmds += 1
if name_cog != "Help":
halp.add_field(name = f'**{name_cog}{nb_cmds}**', value = liste_cmds[2:], inline = False)
cmds_desc = ''
for y in self.client.walk_commands():
if not y.cog_name and not y.hidden:
cmds_desc += (f'{ctx.prefix}{y.name} - {y.help}\n ')
if len(cmds_desc) > 1:
halp.add_field(name = 'Commandes sans catégorie', value = cmds_desc[0:len(cmds_desc)-1], inline = False)
await ctx.message.add_reaction(emoji = '')
await ctx.send(embed = halp)
else:
"""Avertissement si il y a trop d'arguments dans la variable cog"""
if len(cog) > 1:
halp = discord.Embed(title = 'Erreur !', description = "Tu as renseigné trop d'arguments !", color = 0xC41B1B)
await ctx.send(embed = halp)
else:
"""Liste des commandes avec cogs."""
cog = [item.capitalize() for item in cog]
found = False
for x in self.client.cogs:
for y in cog:
if x == y:
halp = discord.Embed(title = f'{cog[0]} - Liste des commandes', description = self.client.cogs[cog[0]].__doc__, color = randint(0, 0xFFFFFF))
for c in self.client.get_cog(y).get_commands():
if not c.hidden:
cmds_help = str(c.help).split("\n")
del cmds_help[0]
backslash = '\n'
halp.add_field(name = f"`{ctx.prefix}{c.name}` - {str(c.help).split(backslash)[0]}", value = f"{''.join(cmds_help)}\u200b", inline = False)
found = True
if not found:
"""Rappel si le cog n'existe pas."""
await ctx.message.add_reaction(emoji = '')
halp = discord.Embed(title = 'Erreur !', description = f"Qu'est ce que {cog[0]} ?", color = 0xC41B1B)
else:
await ctx.message.add_reaction(emoji = '')
await ctx.send('', embed = halp)

139
cogs/internet.py Normal file
View file

@ -0,0 +1,139 @@
import discord, praw, json, requests, datetime
from discord.ext import commands
from random import randint, choice
import time
def setup(client):
client.add_cog(Internet(client))
class Internet(commands.Cog):
"""Commandes relatives à ce qui provient d'internet."""
def __init__(self, client):
self.client = client
@commands.Cog.listener()
async def on_message(self, message):
if message.channel.id == 770805818487865404 or message.channel.id == 772239638240165928: # Le groupe de l'amour ❤❤ -- channel chien/chat
chiens = ["dog", "chien", "potichien"]
chats = ["kat", "mace", "kater", "katze", "sinta", "minoos", "cat", "qitt", "besseh", "katu", "caun", "kazh",
"bisig", "moggy", "kotka", "maow", "gat", "we'sa", "guigna", "kodkod", "mao", "koyangi", "ghjattu", "míw", "pussi",
"gato", "gata", "kato", "kass", "domadh", "demmat", "kissa", "chat", "minou", "piscín", "cath", "k'at'a", "muca", "gali",
"gatos", "popoki", "kike", "chatul", "chatula", "billa", "kat poes", "macska", "cica", "kutjing", "kucing", "köttur",
"gatto", "gattina", "neko", "chma", "pising", "feles", "felix", "kakis", "katé", "qattus", "qattusa", "ngeru", "miz", "felino",
"felina", "muur", "katt", "shimii", "billi", "gorbe", "pusa", "kot", "giat", "pisica", "koshka", "pusi", "macka", "mizhu",
"kotsur", "bisad", "büsi", "chatz", "paka", "muc", "poonai", "puunay", "kocour", "kocka", "maa-oh", "kedi", "kit", "con mêo",
"tchèt", "mouss", "ologbo", "kats", "", "кот", "고양이", "poticha", "😼"]
if message.content.lower() in chiens:
await self._dog(await self.client.get_context(message))
if message.content.lower() in chats:
await self._cat(await self.client.get_context(message))
@commands.command(name='memes', aliases = ['meme'])
async def _memes(self, ctx, *, args = ""):
"""Envois un meme de reddit.\n ➡ Syntaxe: .memes/meme [subreddit]"""
try:
reddit = praw.Reddit(client_id = 'nHPaCR8L_jlmwQ', client_secret = 'tSCjb4QvdiNyCYKmW35SEWhjV8w', user_agent = 'disreddit /u/mylloon, http://localhost:8080')
if args != "": # si il y a un arg différent d'un meme
subredditchoix = args
else: # si il n'y a pas d'arguments
subredditchoix = choice(['memes', 'anime_irl', 'goodanimemes', 'BikiniclienttomTwitter', 'dankmemes', 'DeepFriedMemes',
'educationalmemes', 'funny', 'marvelmemes', 'me_irl', 'meme', 'MemeEconomy', 'Memes_Of_The_Dank', 'MinecraftMemes',
'physicsmemes', 'reactiongifs', 'blackpeopletwitter', 'metal_me_irl', 'bee_irl', '195',
'shittyadviceanimals', 'meirl', '2meirl4meirl', 'AdviceAnimals', 'weirdmemes'])
memes_submissions = reddit.subreddit(subredditchoix).hot()
post_to_pick = randint(1, 10)
for i in range(0, post_to_pick): # i pas important
i = i #retire l'erreur sur vscode
submission = next(x for x in memes_submissions if not x.stickied)
image = ["png", "jpg", "jpeg", "bmp", "gif"]
if submission.url[-3:] in image:
embed = discord.Embed(title = f"r/{subredditchoix} pour {ctx.author.name}", color = randint(0, 0xFFFFFF), description = f"[lien du meme]({submission.url})")
embed.set_footer(text = f"Meme de Reddit")
embed.set_image(url = submission.url)
message = await ctx.send(embed = embed)
else:
await ctx.send(f"```r/{subredditchoix} pour {ctx.author.name}```\n{submission.url}")
message = await ctx.send("```Meme de Reddit```")
await ctx.message.add_reaction(emoji = '')
await message.add_reaction('👍')
return await message.add_reaction('👎')
except Exception as error:
print(f"args: {args}, subreddit: {subredditchoix}, error: {error}")
await ctx.message.add_reaction(emoji = '')
return await ctx.send(f"Ce subreddit est interdit, mis en quarantaine ou n'existe pas. ({subredditchoix})")
def _random_image(self, link):
temps_requete = int(round(time.time() * 1000))
try:
request_data = requests.get(link)
except Exception as e:
raise Exception(f"Une erreur s'est produite lors de la tentative de demande de l'API {link} : {e}")
if not request_data.status_code == 200:
raise Exception(f"Code HTTP {request_data.status_code} au lieu de HTTP 200 à l'appel de {link} : {request_data.text}")
try:
json_data = json.loads(request_data.text)
except Exception as e:
raise Exception(f"Erreur lors de la transformation les données de {link} en json : {e}")
temps_requete = int(round(time.time() * 1000)) - temps_requete
return (json_data, temps_requete)
@commands.command(name='cat', aliases = ['chat'])
async def _cat(self, ctx):
"""Te montre un magnifique chat\n ➡ Syntaxe: .cat/chat"""
if ctx.author.nick:
name = f"{ctx.author.nick} ({ctx.author.name}#{ctx.author.discriminator})"
else:
name = f"{ctx.author.name}"
embed = discord.Embed(title = f"Poticha pour {name}", colour = randint(0, 0xFFFFFF))
cat = self._random_image("http://aws.random.cat/meow")
embed.set_image(url = cat[0]['file'])
embed.set_footer(text = f"random.cat a pris {cat[1]} ms.")
await ctx.message.add_reaction(emoji = '')
message = await ctx.send(embed=embed)
return await message.add_reaction('❤️')
@commands.command(name='dog', aliases = ['chien'])
async def _dog(self, ctx):
"""Te montre un magnifique chien\n ➡ Syntaxe: .dog/chien"""
if ctx.author.nick:
name = f"{ctx.author.nick} ({ctx.author.name}#{ctx.author.discriminator})"
else:
name = f"{ctx.author.name}"
embed = discord.Embed(title = f"Potichien pour {name}", colour = randint(0, 0xFFFFFF))
dog = self._random_image("https://dog.ceo/api/breeds/image/random")
embed.set_image(url = dog[0]['message'])
embed.set_footer(text = f"dog.ceo a pris {dog[1]} ms.")
await ctx.message.add_reaction(emoji = '')
message = await ctx.send(embed=embed)
return await message.add_reaction('❤️')
@commands.command(name='sexe', aliases=['sexes', 'nude', 'nudes', 'nsfw'])
async def _sexe(self, ctx, *, choice_of_nsfw = None):
"""Envois une image coquine. (NSFW)\n ➡ Syntaxe: .sexe/sexes/nude/nudes [butts/boobs]"""
liste_hot = ['butts', 'boobs']
if choice_of_nsfw in liste_hot:
pass
else:
choice_of_nsfw = choice(liste_hot)
if ctx.channel.is_nsfw():
embed = discord.Embed(title = f"{choice_of_nsfw.capitalize()} pour {ctx.author.name}", colour = randint(0, 0xFFFFFF))
nsfw = self._random_image(f'http://api.o{choice_of_nsfw}.ru/noise/')
embed.set_image(url = f"http://media.o{choice_of_nsfw}.ru/{nsfw[0][0]['preview']}")
embed.set_footer(text = f"o{choice_of_nsfw}.ru a pris {nsfw[1]} ms.")
await ctx.message.add_reaction(emoji = '')
await ctx.send(embed = embed)
else:
await ctx.message.add_reaction(emoji = '')
await ctx.send(f"Désolé mais je n'envois ce genre de message seulement dans les salons NSFW !")

565
cogs/music.py Normal file
View file

@ -0,0 +1,565 @@
# -*- coding: utf-8 -*-
"""
Copyright (c) 2019 Valentin B.
https://gist.github.com/vbe0201/ade9b80f2d3b64643d854938d40a0a2d
"""
import asyncio
import functools
import itertools
import math
import random
import discord
import youtube_dl
from async_timeout import timeout
from discord.ext import commands
from random import randint
import lyricsgenius
import time
# Genius API
genius = lyricsgenius.Genius("gmAB9NLNoDACxvcf5IjJKVVgbYx3UJ8CZmdQkFOitRfyFewI6qvZFe62x6EUETpK")
# Silence useless bug reports messages
youtube_dl.utils.bug_reports_message = lambda: ''
def setup(client):
client.add_cog(Music(client))
class VoiceError(Exception):
pass
class YTDLError(Exception):
pass
class YTDLSource(discord.PCMVolumeTransformer):
YTDL_OPTIONS = {
'format': 'bestaudio/best',
'extractaudio': True,
'audioformat': 'mp3',
'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s',
'restrictfilenames': True,
'noplaylist': True,
'nocheckcertificate': True,
'ignoreerrors': False,
'logtostderr': False,
'quiet': True,
'no_warnings': True,
'default_search': 'auto',
'source_address': '0.0.0.0',
}
FFMPEG_OPTIONS = {
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
'options': '-vn',
}
ytdl = youtube_dl.YoutubeDL(YTDL_OPTIONS)
def __init__(self, ctx: commands.Context, source: discord.FFmpegPCMAudio, *, data: dict, volume: float = 0.5):
super().__init__(source, volume)
self.requester = ctx.author
self.channel = ctx.channel
self.data = data
self.uploader = data.get('uploader')
self.uploader_url = data.get('uploader_url')
date = data.get('upload_date')
self.upload_date = date[6:8] + '.' + date[4:6] + '.' + date[0:4]
self.title = data.get('title')
self.thumbnail = data.get('thumbnail')
self.description = data.get('description')
self.duration = self.parse_duration(int(data.get('duration')))
self.tags = data.get('tags')
self.url = data.get('webpage_url')
self.views = data.get('view_count')
self.likes = data.get('like_count')
self.dislikes = data.get('dislike_count')
self.stream_url = data.get('url')
def __str__(self):
return f"**{self.title}** de **{self.uploader}**"
@classmethod
async def create_source(cls, ctx: commands.Context, search: str, *, loop: asyncio.BaseEventLoop = None):
loop = loop or asyncio.get_event_loop()
partial = functools.partial(cls.ytdl.extract_info, search, download=False, process=False)
data = await loop.run_in_executor(None, partial)
if data is None:
raise YTDLError(f"Je n'ai rien trouvé qui corresponde à `{search}`")
if 'entries' not in data:
process_info = data
else:
process_info = None
for entry in data['entries']:
if entry:
process_info = entry
break
if process_info is None:
raise YTDLError(f"Je n'ai rien trouvé qui corresponde à `{search}`")
webpage_url = process_info['webpage_url']
partial = functools.partial(cls.ytdl.extract_info, webpage_url, download=False)
processed_info = await loop.run_in_executor(None, partial)
if processed_info is None:
raise YTDLError(f"Impossible d'obtenir `{webpage_url}`")
if "entries" not in processed_info:
info = processed_info
else:
info = None
while info is None:
try:
info = processed_info['entries'].pop(0)
except IndexError:
raise YTDLError(f"Aucune correspondances pour `{webpage_url}`")
return cls(ctx, discord.FFmpegPCMAudio(info['url'], **cls.FFMPEG_OPTIONS), data=info)
@staticmethod
def parse_duration(duration: int):
minutes, seconds = divmod(duration, 60)
hours, minutes = divmod(minutes, 60)
days, hours = divmod(hours, 24)
duration = []
if days > 0:
duration.append(f"{days} jours,{'' if days <= 1 else 's'}")
if hours > 0:
duration.append(f"{hours} H,{'' if hours <= 1 else 's'}")
if minutes > 0:
duration.append(f"{minutes} min{'' if minutes <= 1 else 's'}")
if seconds > 0:
duration.append(f"{seconds} sec{'' if seconds <= 1 else 's'}")
return ' '.join(duration)
class Song:
__slots__ = ('source', 'requester')
def __init__(self, source: YTDLSource):
self.source = source
self.requester = source.requester
def create_embed(self):
embed = (discord.Embed(title="Joue",
description=f"\n[{self.source.title}]({self.source.url})\n",
color=randint(0, 0xFFFFFF))
.add_field(name="Durée", value=self.source.duration)
.add_field(name="Demandé par", value=self.requester.mention)
.add_field(name="Chaîne", value=f"[{self.source.uploader}]({self.source.uploader_url})")
.set_thumbnail(url=self.source.thumbnail))
return embed
def title(self):
return self.source.title
class SongQueue(asyncio.Queue):
def __getitem__(self, item):
if isinstance(item, slice):
return list(itertools.islice(self._queue, item.start, item.stop, item.step))
else:
return self._queue[item]
def __iter__(self):
return iter(self._queue.__iter__())
def __len__(self):
return self.qsize()
def clear(self):
self._queue.clear()
def shuffle(self):
random.shuffle(self._queue)
def remove(self, index: int):
del self._queue[index]
class VoiceState:
def __init__(self, client: commands.bot, ctx: commands.Context):
self.client = client
self._ctx = ctx
self.current = None
self.voice = None
self.next = asyncio.Event()
self.songs = SongQueue()
self._loop = False
self._volume = 1.0
self.audio_player = client.loop.create_task(self.audio_player_task())
def __del__(self):
self.audio_player.cancel()
@property
def loop(self):
return self._loop
@loop.setter
def loop(self, value: bool):
self._loop = value
@property
def volume(self):
return self._volume
@volume.setter
def volume(self, value: float):
self._volume = value
@property
def is_playing(self):
return self.voice and self.current
async def audio_player_task(self):
while True:
self.next.clear()
if not self.loop:
# Try to get the next song within 3 minutes.
# If no song will be added to the queue in time,
# the player will disconnect due to performance
# reasons.
try:
async with timeout(180): # 3 minutes
self.current = await self.songs.get()
except asyncio.TimeoutError:
self.client.loop.create_task(self.stop())
return
self.current.source.volume = self._volume
self.voice.play(self.current.source, after=self.play_next_song)
await self.current.source.channel.send(embed=self.current.create_embed())
await self.next.wait()
def play_next_song(self, error=None):
if error:
raise VoiceError(str(error))
self.next.set()
def skip(self):
if self.is_playing:
self.voice.stop()
async def stop(self):
self.songs.clear()
if self.voice:
await self.voice.disconnect()
self.voice = None
class Music(commands.Cog):
"""Commandes relatives à la musique - © vbe0201."""
def __init__(self, client: commands.bot):
self.client = client
self.voice_states = {}
def get_voice_state(self, ctx: commands.Context):
state = self.voice_states.get(ctx.guild.id)
if not state:
state = VoiceState(self.client, ctx)
self.voice_states[ctx.guild.id] = state
return state
def cog_unload(self):
for state in self.voice_states.values():
self.client.loop.create_task(state.stop())
def cog_check(self, ctx: commands.Context):
if not ctx.guild:
raise commands.NoPrivateMessage("Je ne fais pas de musiques en DM.")
return True
async def cog_before_invoke(self, ctx: commands.Context):
ctx.voice_state = self.get_voice_state(ctx)
async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError):
await ctx.send(f"Une erreur est survenue : {str(error)}")
@commands.command(name='join', aliases=['j'], invoke_without_subcommand=True)
async def _summon(self, ctx: commands.Context, *, channel: discord.VoiceChannel = None):
"""Se connecte au salon vocal.\n ➡ Syntaxe: .connect/join"""
if not channel and not ctx.author.voice:
await ctx.send("Aucun channel à rejoindre. Connecte toi dans un vocal ou donne-moi son id.")
raise VoiceError("Vous n'êtes pas connecté à un channel vocal et n'avez spécifié aucun channel à rejoindre.")
destination = channel or ctx.author.voice.channel
await ctx.send(f":thumbsup: **Connecté à __{destination}__**")
if ctx.voice_state.voice:
await ctx.voice_state.voice.move_to(destination)
return
ctx.voice_state.voice = await destination.connect()
@commands.command(name='stop', aliases=['disconnect', 'dc'])
async def _leave(self, ctx: commands.Context):
"""Arrête la chanson en cours de lecture et quitte le salon vocal.\n ➡ Syntaxe: .disconnect/dc/stop"""
if not ctx.voice_state.voice:
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose ou `.join [id]` pour me connecter à un salon vocal.", color = 0xC41B1B)
embed.set_author(name = "Je ne suis connecté à aucun vocal.")
return await ctx.send(embed = embed)
await ctx.voice_state.stop()
del self.voice_states[ctx.guild.id]
await ctx.send("📭 **Déconnecté du salon**")
@commands.command(name='volume', aliases=['vol'])
async def _volume(self, ctx: commands.Context, *, volume: int = False):
"""Modifie le volume du bot (entre 1 et 100).\n ➡ Syntaxe: .volume/vol [1;100]"""
if not ctx.voice_state.is_playing:
return await ctx.send("Rien n'est joué pour le moment.")
if not volume:
return await ctx.send(f"Le volume est à **{ctx.voice_state.volume * 100}%**")
if 0 > volume > 100:
return await ctx.send("Le volume doit être compris entre 0 et 100.")
ctx.voice_state.volume = volume / 100
await ctx.send(f"Volume réglé sur **{volume}%**")
@commands.command(name='now', aliases=['current', 'playing', 'np'])
async def _now(self, ctx: commands.Context):
"""Affiche des informations sur la chanson en cours de lecture.\n ➡ Syntaxe: .now/current/playing/np"""
await ctx.send(embed=ctx.voice_state.current.create_embed())
@commands.command(name='pause')
async def _pause(self, ctx: commands.Context):
"""Mets en pause de la chanson en cours de lecture."""
if not ctx.voice_state.is_playing and ctx.voice_state.voice.is_playing():
ctx.voice_state.voice.pause()
await ctx.message.add_reaction('')
await ctx.send(f"**`{ctx.author}`** met en pause la chanson en cours.")
else:
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
embed.set_author(name = "Je ne joue rien en ce moment !")
return await ctx.send(embed = embed)
@commands.command(name='resume')
async def _resume(self, ctx: commands.Context):
"""Reprends la chanson en pause."""
if not ctx.voice_state.is_playing and ctx.voice_state.voice.is_paused():
ctx.voice_state.voice.resume()
await ctx.message.add_reaction('')
await ctx.send(f"**`{ctx.author}`** relance la chanson.")
else:
if ctx.voice_state.is_playing:
embed = discord.Embed(description = "Tape `.pause` pour mettre en pause la chanson.", color = 0xC41B1B)
embed.set_author(name = "Je suis déjà en lecture !")
return await ctx.send(embed = embed)
else:
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose ou `.join [id]` pour me connecter à un salon vocal.", color = 0xC41B1B)
embed.set_author(name = "Je ne suis connecté à aucun vocal.")
return await ctx.send(embed = embed)
@commands.command(name='skip', aliases=['s'])
async def _skip(self, ctx: commands.Context):
"""Passe la chanson.\n ➡ Syntaxe: .skip/s"""
if not ctx.voice_state.is_playing:
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
embed.set_author(name = "Je ne joue rien en ce moment !")
return await ctx.send(embed = embed)
await ctx.message.add_reaction('')
ctx.voice_state.skip()
await ctx.send(f"**`{ctx.author}`**: Passe la chanson !")
@commands.command(name='queue', aliases=['q', 'playlist'])
async def _queue(self, ctx: commands.Context, *, page: int = 1):
"""Affiche la file d'attente des chansons à venir.\n ➡ Syntaxe: .queue/q/playlist [page]"""
if len(ctx.voice_state.songs) == 0:
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
embed.set_author(name = "Il n'y a plus de chanson à venir dans la playlist.")
return await ctx.send(embed = embed)
items_per_page = 10
pages = math.ceil(len(ctx.voice_state.songs) / items_per_page)
if page > pages:
embed = discord.Embed(description = "Tape `.play <chanson>` pour rajouter encore de la musique.", color = 0xC41B1B)
embed.set_author(name = "Il n'y a pas autant de pages")
return await ctx.send(embed = embed)
start = (page - 1) * items_per_page
end = start + items_per_page
queue = ''
for i, song in enumerate(ctx.voice_state.songs[start:end], start=start):
queue += f"`{i + 1}.` [**{song.source.title}**]({song.source.url})\n"
embed = (discord.Embed(description=f"**{len(ctx.voice_state.songs)} piste{'s' if len(ctx.voice_state.songs)>1 else ''} :**\n\n{queue}", color = randint(0, 0xFFFFFF))
.set_footer(text=f"Page {page}/{pages}"))
await ctx.send(embed=embed)
@commands.command(name='shuffle')
async def _shuffle(self, ctx: commands.Context):
"""Mélange la file d'attente."""
if len(ctx.voice_state.songs) == 0:
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
embed.set_author(name = "La file est vide.")
return await ctx.send(embed = embed)
ctx.voice_state.songs.shuffle()
await ctx.message.add_reaction('')
@commands.command(name='remove')
async def _remove(self, ctx: commands.Context, index: int):
"""Supprime une chanson de la file d'attente."""
if len(ctx.voice_state.songs) == 0:
return await ctx.send("File vide.")
ctx.voice_state.songs.remove(index - 1)
await ctx.message.add_reaction('')
await ctx.send("Chanson sélectionnée supprimée de la file d'attente.")
@commands.command(name='loop', aliases=['repeat'])
async def _loop(self, ctx: commands.Context):
"""Répète la chanson actuellement en lecture.\n ➡ Syntaxe: .loop/repeat"""
if not ctx.voice_state.is_playing:
embed = discord.Embed(description = "Tape `.play <chanson>` pour jouer quelque chose.", color = 0xC41B1B)
embed.set_author(name = "Je ne joue rien en ce moment !")
return await ctx.send(embed = embed)
# Inverse boolean value to loop and unloop.
ctx.voice_state.loop = not ctx.voice_state.loop
await ctx.message.add_reaction('')
await ctx.send("La chanson change d'état.")
@commands.command(name='play', aliases=['p'])
async def _play(self, ctx: commands.Context, *, search: str):
"""Recherche une chanson sur les sites compatibles avec YoutubeDL si aucun URL n'est donné et l'ajoute à la file d'attente.\n ➡ Syntaxe: .play/p"""
if not ctx.voice_state.voice:
await ctx.invoke(self._summon)
async with ctx.typing():
try:
source = await YTDLSource.create_source(ctx, search, loop=self.client.loop)
except YTDLError as e:
await ctx.send(f"Une erreur s'est produite lors du traitement de cette demande : {str(e)}")
else:
song = Song(source)
await ctx.voice_state.songs.put(song)
await ctx.send(f"En file d'attente {str(source)}")
@_summon.before_invoke
@_play.before_invoke
async def ensure_voice_state(self, ctx: commands.Context):
if not ctx.author.voice or not ctx.author.voice.channel:
raise commands.CommandError("Vous n'êtes connecté à aucun channel vocal.")
if ctx.voice_client:
if ctx.voice_client.channel != ctx.author.voice.channel:
raise commands.CommandError("Le bot est déjà dans un channel vocal.")
@commands.command(name='lyrics', aliases = ['l', 'lyric'])
async def _lyrics(self, ctx, *, song: str = None):
"""Affiche les paroles de la musique en cours, ou de la chanson spécifiée.\n ➡ Syntaxe: .lyrics/lyric/l (musique)"""
if song or ctx.voice_state.is_playing:
if not song:
song = f"{ctx.voice_state.current.title()}"
if " romanized" in song:
message = await ctx.send(f":mag: **Cherche les paroles romanisées de ** `{song.replace(' romanized', '')}`")
else:
message = await ctx.send(f":mag: **Cherche les paroles de ** `{song}`")
temps_requete = int(round(time.time() * 1000))
song_genius = genius.search_song(song)
couleur_embed = randint(0, 0xFFFFFF)
try:
paroles = song_genius.lyrics
except:
await ctx.message.add_reaction(emoji = '')
return await message.edit(content = f"Pas de résultats trouvés pour `{song}`.")
lignetotal = ""
premierembed = True
if len(paroles) > 7500:
await ctx.message.add_reaction(emoji = '')
return await message.edit(content = f"Désolé, les paroles sont trop longues pour être affichés (lien vers la page des paroles : {song_genius.url}).")
title_first_embed = f"Paroles de {song_genius.title} par {song_genius.artist}."
desc_first_embed = f"[Lien vers les paroles sur le site]({song_genius.url})"
type_de_comptage = "\n\n" if paroles.count("\n\n") > 2 else "\n"
for ligne in paroles.split(type_de_comptage):
if len(ligne) >= 2048:
type_de_comptage = "\n"
for ligne in paroles.split(type_de_comptage):
if len(f"{lignetotal}{type_de_comptage}{ligne}") < 1900:
lignetotal = f"{lignetotal}{type_de_comptage}{self.ligne_formatage(ligne)}"
else:
if premierembed == True:
premierembed = False
embed = discord.Embed(title = title_first_embed, description = f"{desc_first_embed}{lignetotal}", color = couleur_embed)
embed.set_thumbnail(url = song_genius.song_art_image_url)
await message.edit(embed = embed)
else:
embed = discord.Embed(description = lignetotal, color = couleur_embed)
await ctx.send(embed = embed)
lignetotal = f"{self.ligne_formatage(ligne)}"
temps_requete = int(round(time.time() * 1000)) - temps_requete
footer_embed = f"Pour {self.user_or_nick(ctx.author)} par Genius en {round(temps_requete / 1000, 2)} s."
await ctx.message.add_reaction(emoji = '')
if premierembed == True:
premierembed = False
embed = discord.Embed(title = title_first_embed, description = f"{desc_first_embed}{lignetotal}", color = couleur_embed)
embed.set_footer(icon_url = ctx.author.avatar_url, text = footer_embed)
return await message.edit(embed = embed)
else:
embed = discord.Embed(description = lignetotal, color = couleur_embed)
embed.set_footer(icon_url = ctx.author.avatar_url, text = footer_embed)
return await ctx.send(embed = embed)
else:
await ctx.message.add_reaction(emoji = '')
await ctx.send("Aucune musique demandé... `.lyrics/l/lyrics <song>`.")
def ligne_formatage(self, ligne):
liste_balise = [
('[Hook', '[Accroche'), ('[Verse', '[Couplet'), ('[Chorus', '[Chœur'),
('[Bridge', '[Pont'),('[Pre-Chorus', '[Pré-chœur'), ('[Post-Chorus', '[Post-chœur')
]
for balises in liste_balise:
ligne = ligne.replace(balises[0], balises[1])
return ligne
def user_or_nick(self, user):
if user.nick:
return f"{user.nick} ({user.name}#{user.discriminator})"
else:
return f"{user.name}#{user.discriminator}"
@commands.command(name='lyricsromanized', aliases = ['lr', 'lyricromanized'], hidden = True)
async def _lyricsromanized(self, ctx, *, song: str = None):
await ctx.invoke(self.client.get_command("lyrics"), song = f"{song} romanized" if song else song)

337
cogs/utils.py Normal file
View file

@ -0,0 +1,337 @@
import discord, pytz, time
from discord.ext import commands
from random import randint, shuffle
from datetime import datetime
from pytz import timezone
import re
import asyncio
def setup(client):
client.add_cog(Utils(client))
class Utils(commands.Cog):
"""Commandes essentielles."""
def __init__(self, client):
self.client = client
@commands.command(name='ping')
async def _ping(self, ctx, *, question = '0'):
"""Affiche mon ping.\n ➡ Syntaxe: .ping [help]"""
if question == 'help':
return await ctx.send(embed = discord.Embed(color = randint(0, 0xFFFFFF), description = ":hourglass: correspond au temps entre deux battements de cœurs (en millisecondes)\n\n:stopwatch: correspond au temps que met le client a calculer le ping (en millisecondes)\n\n:heartbeat: correspond au temps que met le client a réagir au messages (en millisecondes)"))
else:
now = int(round(time.time() * 1000))
ping = now - int(round(ctx.message.created_at.timestamp() * 1000))
embed = discord.Embed(description = 'Pinging...')
message = await ctx.send(embed = embed)
ping2 = int(round(time.time() * 1000)) - now
await message.edit(embed = discord.Embed(color = randint(0, 0xFFFFFF), description = f':hourglass: {round(self.client.latency * 1000)}ms\n\n:stopwatch: {ping2}ms\n\n:heartbeat: {ping}ms'))
await ctx.message.add_reaction(emoji = '')
@commands.command(name='avatar')
async def _avatar(self, ctx, *, user = '0'):
"""Affiche ton avatar ou celui que tu mentionnes.\n ➡ Syntaxe: .avatar [user]"""
if user == '0':
user = ctx.author
else:
user = self.client.get_user(int(user[2:-1].replace("!","")))
await ctx.message.add_reaction(emoji = '')
embed = discord.Embed(description = f"[lien vers la photo de profil]({user.avatar_url}) de {user.mention}", color = randint(0, 0xFFFFFF))
embed.set_author(name = f"Photo de profil de {user.name}")
embed.set_image(url = user.avatar_url)
await ctx.send(embed = embed)
@commands.command(name='calc')
async def _calc(self, ctx, *, msg):
"""Calculatrice.\n ➡ Syntaxe: .calc <calcul>"""
equation = msg.replace('^', '**').replace('x', '*').replace('×', '*').replace('÷', '/').replace('', '>=').replace('', '<=')
try:
try:
if '=' in equation:
if '<' in equation:
left = eval(equation.split("<=")[0])
right = eval(equation.split("<=")[1])
answer = str(left <= right)
elif '>' in equation:
left = eval(equation.split(">=")[0])
right = eval(equation.split(">=")[1])
answer = str(left >= right)
else:
left = eval(equation.split("=")[0])
right = eval(equation.split("=")[1])
answer = str(left == right)
else:
answer = str(eval(equation))
except ZeroDivisionError:
return await ctx.send("Tu ne peux pas divisé par 0.")
except TypeError:
return await ctx.send("Requête de calcul invalide.")
if '.' in answer:
aftercomma = answer.split(".")[1]
if len(aftercomma) > 2:
answer = str(round(float(answer),2))
equation = f"'{equation}' arrondi à 2"
equation = equation.replace('*', '×').replace('/', '÷').replace('>=', '').replace('<=', '')
embed = discord.Embed(color = randint(0, 0xFFFFFF), title = 'Calculatrice')
embed.set_footer(text = ctx.author)
embed.add_field(name = 'Calcul :', value = equation, inline = False)
embed.add_field(name = 'Réponse :', value = answer.replace('False', 'Faux').replace('True', 'Vrai'), inline = False)
await ctx.message.add_reaction(emoji = '')
await ctx.send(content = None, embed = embed)
@_calc.error
async def _calc_error(self, ctx, error):
await ctx.send("Tu n'as pas spécifié de calcul.")
@commands.command(name='syntax')
async def _syntax(self, ctx):
"""Informations pour bien éditer son texte."""
syntaxe = "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("```Js\n")
syntaxe += discord.utils.escape_markdown("//code en js (possible de remplacer 'js' par d'autres languages . adaptez le !)\n")
syntaxe += discord.utils.escape_markdown('console.log("hi");\n')
syntaxe += discord.utils.escape_markdown("```\n")
syntaxe += "```Js\n"
syntaxe += "//code en js (possible de remplacer 'js' par d'autres languages . adaptez le !)\n"
syntaxe += 'console.log("hi");\n'
syntaxe += "```\n"
syntaxe += "Si ton code est trop long, mets le sur <https://pastebin.com/>\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("`code sur une seule ligne`\n")
syntaxe += "`code sur une seule ligne`\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("*texte en italique*\n")
syntaxe += "*texte en italique*\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("**text en gras**\n")
syntaxe += "**text en gras**\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("<<https://www.youtube.com/watch?v=GhuYKL5NUYg>>\n")
syntaxe += "Un lien entre crochet, ça empêche Discord de rajouté son intégration automatique (mais le lien fonctionnera toujours).\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("__texte souligné__\n")
syntaxe += "__texte souligné__\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("~~texte barré~~\n")
syntaxe += "~~texte barré~~\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("~~__***text en italique-gras-souligné-barré***__~~\n")
syntaxe += "~~__***text en italique-gras-souligné-barré***__~~\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("\:joy: <- l'emoji ne va pas fonctionné grâce au \ \n")
syntaxe += "\:joy: <- l'emoji ne va pas fonctionné grâce au \ \n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown("> cette ligne est cité\npas celle là\n")
syntaxe += "> cette ligne est cité\npas celle là\n"
syntaxe += "-----------------------------------------------------\n"
syntaxe += discord.utils.escape_markdown(">>> cette ligne est cité\ncelle là aussi (et elles le seront toutes!)\n")
syntaxe += ">>> cette ligne est cité\ncelle là aussi (et elles le seront toutes!)\n"
await ctx.message.add_reaction(emoji = '')
await ctx.send(syntaxe)
@commands.command(name='memo', aliases = ['note'])
async def _memo(self, ctx, *, text):
"""T'envoie un petit memo par message privé.\n ➡ Syntaxe: .memo/note <message>"""
if len(text) <= 5:
await ctx.message.add_reaction(emoji = '')
return await ctx.send("Ta note doit au moins faire 5 caractères.")
elif len(text) >= 2048:
await ctx.message.add_reaction(emoji = '')
return await ctx.send("Ta note doit faire moins de 2048 caractères.")
else:
await ctx.message.delete()
embed = discord.Embed(description = text, color = randint(0, 0xFFFFFF))
embed.set_author(name = "Mémo", icon_url = ctx.author.avatar_url)
embed.set_footer(text = f'📝 le {datetime.now(pytz.timezone("Europe/Paris")).strftime("%d/%m/%Y à %H:%M:%S")}')
await ctx.author.send(embed = embed)
return await ctx.send("Tu viens de recevoir ton mémo !", delete_after = 5)
@_memo.error
async def _note_error(self, ctx, error):
if str(error) == "text is a required argument that is missing.":
await ctx.send("Vous devez renseigner un message : `.note/memo <message>`.")
@commands.command(name='infos', aliases = ['info'])
async def _infos(self, ctx):
"""Donne des infos sur le bot.\n ➡ Syntaxe: .infos/info"""
appinfo = await self.client.application_info()
embed = discord.Embed(color = randint(0, 0xFFFFFF))
embed.set_author(name = appinfo.name, icon_url = self.client.user.avatar_url)
total_online = len({m.id for m in self.client.get_all_members() if m.status is discord.Status.online})
total_unique = len(self.client.users)
voice_channels = []
text_channels = []
for guild in self.client.guilds:
voice_channels.extend(guild.voice_channels)
text_channels.extend(guild.text_channels)
text = len(text_channels)
voice = len(voice_channels)
embed.add_field(name = "Dev", value = f"[{appinfo.owner}](https://github.com/Mylloon)")
embed.add_field(name = "Serveurs", value = len(self.client.guilds))
embed.add_field(name = "Membres", value = f"{total_unique} au total\n{total_online} en ligne")
embed.add_field(name = "Channels", value = f"{text} textuelles\n{voice} vocales")
embed.set_footer(text = f"Basé sur discord.py {discord.__version__}")
await ctx.message.add_reaction(emoji = '')
await ctx.send(embed = embed)
def _map_list_among_us(self, map):
maps = {}
maps["skeld"] = ["skeld", "the skeld", "theskeld"]
maps["mira"] = ["mira", "mira hq", "mirahq"]
maps["polus"] = ["polus"]
if map == "all":
return maps["skeld"] + maps["mira"] + maps["polus"]
return maps[map]
@commands.command(name='among', hidden = True)
async def _among(self, ctx, *, args = ""):
if not args == "":
args = args.split()
del args[0]
args = " ".join(args)
if args.lower() in self._map_list_among_us("all"):
await ctx.invoke(self.client.get_command("amongus"), map=args)
else:
await ctx.invoke(self.client.get_command("amongus"))
else:
await ctx.message.add_reaction(emoji = '')
@commands.command(name='amongus')
async def _amongus(self, ctx, *, map = "0"):
"""Affiche la carte voulue d'Among Us.\n ➡ Syntaxe: .amongus <carte>"""
if map.lower() in self._map_list_among_us("mira"):
image = "https://i.imgur.com/6ijrH1h.jpg"
embed = discord.Embed(title = f"Map Mira HQ d'Among Us", color = randint(0, 0xFFFFFF), description = f"[lien de l'image]({image})")
embed.set_image(url = image)
await ctx.send(embed = embed)
await ctx.message.add_reaction(emoji = '')
elif map.lower() in self._map_list_among_us("polus"):
image = "https://i.imgur.com/mhFmcw3.jpg"
embed = discord.Embed(title = f"Map Polus d'Among Us", color = randint(0, 0xFFFFFF), description = f"[lien de l'image]({image})")
embed.set_image(url = image)
await ctx.send(embed = embed)
await ctx.message.add_reaction(emoji = '')
elif map.lower() in self._map_list_among_us("skeld"):
image = "https://i.imgur.com/OSXI4Zv.jpg"
embed = discord.Embed(title = f"Map The Skeld d'Among Us", color = randint(0, 0xFFFFFF), description = f"[lien de l'image]({image})")
embed.set_image(url = image)
await ctx.send(embed = embed)
await ctx.message.add_reaction(emoji = '')
else:
await ctx.send("`.amongus <mira/polus/skeld>`")
@commands.command(name='whois')
async def _whois(self, ctx, *user: discord.Member):
"""Affiche les infos sur l'utilisateur.\n ➡ Syntaxe: .whois [user]"""
if len(user) <= 1:
if user == ():
user = [ctx.author]
nom = f"{user[0].name}#{user[0].discriminator}"
if user[0].nick:
nom = f"{user[0].nick} ({user[0].name}#{user[0].discriminator})"
embed = discord.Embed(color = randint(0, 0xFFFFFF)).set_author(name = nom, icon_url = user[0].avatar_url)
embed.add_field(name = "ID", value = user[0].id)
value = str(user[0].created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
embed.add_field(name = "Compte créé le", value = f"{value[0][8:]}/{value[0][5:-3]}/{value[0][:4]} à {value[1]}")
embed.add_field(name = "Âge du compte", value = self._age_layout(self._get_age(user[0].created_at)))
embed.add_field(name = "Mention", value = user[0].mention)
value = str(user[0].joined_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
embed.add_field(name = "Serveur rejoint le", value = f"{value[0][8:]}/{value[0][5:-3]}/{value[0][:4]} à {value[1]}")
embed.add_field(name = "Est sur le serveur depuis", value = self._age_layout(self._get_age(user[0].joined_at)))
await ctx.message.add_reaction(emoji = '')
return await ctx.send(embed = embed)
await ctx.send("Tu mentionnes trop d'utilisateurs : `.whois [@Membre]`")
def _get_age(self, date):
joursRestants = datetime.now() - date
years = joursRestants.total_seconds() / (365.242 * 24 * 3600)
months = (years - int(years)) * 12
days = (months - int(months)) * (365.242 / 12)
hours = (days - int(days)) * 24
minutes = (hours - int(hours)) * 60
seconds = (minutes - int(minutes)) * 60
return (int(years), int(months), int(days), int(hours), int(minutes), int(seconds))
def _age_layout(self, tuple):
time = {}
time[0], time[1], time[2], time[3], time[4], time[5] = "an", "mois", "jour", "heure", "minute", "seconde"
for i in range(len(tuple)):
if tuple[i] > 1 and i != 1:
time[i] = time[i] + "s"
message = ""
if tuple[5] > 0: # pour les secondes
affichage = [5] # on affiche que : seconde
if tuple[4] > 0:
affichage = [4, 5] # on affiche : minute + seconde
if tuple[3] > 0:
affichage = [3, 4, 5] # on affiche : heure + minute + seconde
if tuple[2] > 0:
affichage = [2, 3, 4] # on affiche : jour + heure + minute
if tuple[1] > 0:
affichage = [1, 2, 3] # on affiche : mois + jour + heure
if tuple[0] > 0:
affichage = [0, 1, 3] # on affiche : an + mois + heure
for i in affichage:
message = message + f", {tuple[i]} {time[i]}"
return message[2:]
@commands.command(name='sondage')
async def _sondage(self, ctx, *args):
"""Fais un sondage.\n ➡ Syntaxe: .sondage "<Question>" "<Proposition1>" "<Proposition...>" "<Proposition20>" """
args = list(args)
if len(args) > 2:
question = args[0].replace("<@!", "").replace(">", "").replace("<@", "")
for i in re.findall(r'\d+', question):
ii = self.user_or_nick(ctx.author.guild.get_member(int(i)))
try:
question = question.replace(i, ii)
except:
pass
propositions = args[1:]
if len(propositions) <= 20:
message = ""
emojis = {}
emojis[0] = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '🔟']
emojis[1] = [
'🟤', '🔴', '🟠', '🟡', '🟢', '🔵', '🟣', '🔘', '', '💜',
'🟫', '🟥', '🟧', '🟨', '🟩', '🟦', '🟪', '🔳', '🧡', '💙'
]
mixable = True
if len(propositions) <= 10:
emojis_chosen = emojis[randint(0, len(emojis) - 1)]
emojis_chosen = emojis_chosen[:10]
if len(propositions) <= 8:
emojis_chosen = emojis_chosen[:8]
else:
emojis_chosen = emojis[randint(1, len(emojis) - 1)]
if emojis[0][0] in emojis_chosen: # rajouter ici les listes qui ne doivent pas être mélanger
mixable = False
if mixable:
shuffle(emojis_chosen)
for i in range(len(args[1:])):
message += f"{emojis_chosen[i]} -> {propositions[i]}\n"
embed = discord.Embed(title = question, description = message,color = randint(0, 0xFFFFFF)).set_footer(text = self.user_or_nick(ctx.author), icon_url = ctx.author.avatar_url)
sondage = await ctx.send(embed = embed)
for i in range(len(args[1:])):
await sondage.add_reaction(emoji = emojis_chosen[i])
return await ctx.message.add_reaction(emoji = '')
else:
return await ctx.send(f"Désolé, mais tu as mis trop de possibilités (maximum : 20)")
else:
return await ctx.send(f'Désolé, mais il manque des arguments : `.sondage "<Question>" "<Proposition1>" "<Proposition...>" "<Proposition20>"`')
def user_or_nick(self, user):
if user.nick:
return f"{user.nick} ({user.name}#{user.discriminator})"
else:
return f"{user.name}#{user.discriminator}"

180
main.py Normal file
View file

@ -0,0 +1,180 @@
print("Connexion à Discord...")
import discord, re, pytz
from discord.ext import commands
from random import randint, choice
from datetime import datetime, timedelta
from pytz import timezone
from setup import token
client = commands.Bot(command_prefix = ".", case_insensitive = True, intents = discord.Intents.all())
@client.event
async def on_connect():
print(f"Connecté avec le token : {token}.")
print("Chargement des extensions & librairie...")
client.load_extension("cogs.help")
client.load_extension("cogs.utils")
client.load_extension("cogs.internet")
client.load_extension("cogs.music")
client.load_extension("cogs.games")
client.load_extension("cogs.fun")
@client.event
async def on_ready():
await client.change_presence(status = discord.Status.online, activity = discord.Activity(name = ".help", type = discord.ActivityType.playing))
print("Bot prêt.")
channel = client.get_channel(742564480050790512)
await channel.send("Le bot a bien démarré.")
@client.event
async def on_member_join(member):
if member.guild.id == 441208120644075520: # Confrérie du Kassoulait
if member.bot == True:
role = discord.utils.get(member.guild.roles, name = "Bot")
else:
role = discord.utils.get(member.guild.roles, name = "Copain")
await member.add_roles(role)
try:
await member.send(f"Coucou **{member.name}** sur {member.guild.name} ! 🥰\n\nTu as le rôle **{role}** 💖!")
except:
pass
channel = client.get_channel(741639570172674120) # salons des arrivées
switch = {
0: f"Bienvenue, {member.mention}. On espère que tu as apporté de la pizza.",
1: f"C'est un plaisir de te voir, {member.mention}.",
2: f"{member.mention} vient juste d'arriver !",
3: f"{member.mention} vient juste d'atterrir.",
4: f"{member.mention} vient de se glisser dans le serveur.",
5: f"{member.mention} a bondi dans le serveur.",
6: f"Contents de te voir, {member.mention}.",
7: f"{member.mention} est arrivé(e).",
8: f"Tout le monde, accueillez comme il se doit {member.mention} !",
9: f"Youhou, tu as réussi, {member.mention} !",
10: f"{member.mention} a rejoint le groupe.",
}
message = await channel.send("...") # évite d'envoyer une notification
await message.edit(content = choice(switch))
@client.event
async def on_member_remove(member):
if member.guild.id == 441208120644075520: # Confrérie du Kassoulait
channel = client.get_channel(741639570172674120) # salons des arrivées
await channel.send(f"{member.mention} vient de quitter le serveur.")
@client.event
async def on_raw_reaction_add(payload):
if payload.message_id == 644922358745792512: # Règles de la Confrérie du Kassoulait
if payload.emoji.name == '':
role = discord.utils.get(payload.member.guild.roles, name="règles-acceptés")
await payload.member.add_roles(role)
@client.event
async def on_raw_reaction_remove(payload):
if payload.message_id == 644922358745792512: # Règles de la Confrérie du Kassoulait
if payload.emoji.name == '':
guild = discord.utils.find(lambda g : g.id == payload.guild_id, client.guilds)
member = discord.utils.find(lambda m: m.id == payload.user_id, guild.members)
role = discord.utils.get(guild.roles, name="règles-acceptés")
await member.remove_roles(role)
@client.event
async def on_command_error(ctx, error):
if not ctx.invoked_with.startswith('.'):
await ctx.message.add_reaction(emoji = '')
print(error)
@client.event
async def on_message(message):
await client.process_commands(message)
if message.author == client.user:
return
if client.user.mention == message.content.replace("!",""):
ctx = await client.get_context(message)
prefix = await client.get_prefix(message)
await ctx.send(f">>> Coucou !\nMon préfix est `{prefix}` et ma commande d'aide est `{prefix}help`")
urls = re.findall(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', message.content)
for i in range(len(urls)):
if urls[i].startswith("https://discordapp.com/channels/") or urls[i].startswith("https://discord.com/channels/") or urls[i].startswith("https://ptb.discordapp.com/"):
link = urls[i]
linkURL = link
if link.startswith("https://discord.com/channels/"):
link = f'000{link}'
if link.startswith("https://ptb.discordapp.com/"):
link = link[4:]
if "@me" in urls[i]:
return await message.channel.send("Je ne cite pas les messages privés.", delete_after = 5)
try:
if int(link[32:-38]) == message.guild.id:
msgID = await client.get_channel(int(link[51:-19])).fetch_message(int(link[70:]))
if len(msgID.content) > 0:
embed = discord.Embed(description = msgID.content)
else:
return # si le message ne contient pas de mots (image? vidéo? intégration?)
embed.add_field(name = "Auteur", value = msgID.author.mention, inline=True)
embed.add_field(name = "Channel", value = msgID.channel.mention, inline=True)
embed.add_field(name = "Message", value = f"[Aller au message]({linkURL})", inline=True)
embed.set_author(name = "Citation", icon_url = msgID.author.avatar_url)
icon_url = message.author.avatar_url
date_1 = str(msgID.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
edit = ""
if msgID.edited_at:
date_edit = str(msgID.edited_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
edit = f"(Dernier edit : {date_edit[0][8:]}/{date_edit[0][5:-3]}/{date_edit[0][:4]} à {date_edit[1]})"
message_1 = f"Date : {date_1[0][8:]}/{date_1[0][5:-3]}/{date_1[0][:4]} à {date_1[1]} {edit}"
date_2 = str(message.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').split()
date_2 = f"{date_2[0][8:]}/{date_2[0][5:-3]}/{date_2[0][:4]} à {date_2[1]}"
embed.set_footer(icon_url = icon_url, text = f"{message_1}\nCité par {user_or_nick(message.author)} le {date_2}")
await message.channel.send(embed = embed)
if message.content == linkURL.replace(' ',''):
await message.delete()
except Exception as e:
e = str(e)
if not "invalid literal for int() with base 10:" in e or not "404 Not Found (error code: 10008)" in e: # faute de frappe / message supprimé
print(e)
@client.event
async def on_message_delete(message):
if message.author.guild.id == 441208120644075520: # Confrérie du Kassoulait
prefix = await client.get_prefix(message)
if not (
message.content.startswith(f"{prefix}note") or
message.content.startswith(f"{prefix}memo") or
len(re.findall(".com/channels/", message.content)) != 0 or
client.user.id is message.author.id
):
user_suppressed = None
async for entry in message.guild.audit_logs(limit=1):
if (datetime.now() - entry.created_at).seconds < 5 and str(entry.action) == 'AuditLogAction.message_delete':
user_suppressed = entry.user
channel = client.get_channel(742588187456831659)
embed = discord.Embed(description = f"{message.content}")
embed.set_author(name = user_or_nick(message.author), icon_url = message.author.avatar_url)
if not user_suppressed:
embed.set_footer(text = f"Channel: #{message.channel.name} | Date : {str(message.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').replace(' ', ' à ')}\nSupprimé le {datetime.now(pytz.timezone('Europe/Paris')).strftime('%d/%m/%Y à %H:%M:%S')}")
else:
embed.set_footer(icon_url = user_suppressed.avatar_url, text = f"Channel: #{message.channel.name} | Date : {str(message.created_at.astimezone(timezone('Europe/Paris')))[:-13].replace('-', '/').replace(' ', ' à ')}\nSupprimé par {user_or_nick(user_suppressed)} le {datetime.now(pytz.timezone('Europe/Paris')).strftime('%d/%m/%Y à %H:%M:%S')}")
await channel.send(embed = embed)
# ne fonctionne pas quand un message a été supprimé avant que le bot ai démarré
# info sur la personne qui a supprimé ne fonctionne pas si il a supprimé un message auparavant (les logs se rajoute a un log deja existant)
def user_or_nick(user):
if user.nick:
return f"{user.nick} ({user.name}#{user.discriminator})"
else:
return f"{user.name}#{user.discriminator}"
client.run(token)

6
requirements.txt Normal file
View file

@ -0,0 +1,6 @@
discord.py[voice]==1.5.1 # discord
async-timeout==3.0.1 # discord
pytz==2020.4 # timezone
praw==7.1.0 # reddit
youtube-dl==2020.11.17 # music
git+https://github.com/johnwmillr/LyricsGenius.git # lyrics