diff --git a/.idea/cogue.iml b/.idea/cogue.iml deleted file mode 100755 index 6711606..0000000 --- a/.idea/cogue.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100755 index c23ecac..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100755 index 4e1dbee..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100755 index 2a6e1cb..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100755 index 5650cde..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,932 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - args_ - utc = - os_info - rigole - bobon - fast - requests - joke - time - clock - choic - edit - ctx - print( - delete - message - ping - e - you cant - avatar - args - do - warn - is_owner - thuna - wi - str - 269156684155453451 - print - list - - - - - - - - - - - true - DEFINITION_ORDER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - project - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1495903833631 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - file://$PROJECT_DIR$/cogs/admin.py - - - file://$PROJECT_DIR$/cogs/admin.py - 42 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/bot.py b/bot.py index 58d21f8..021011d 100755 --- a/bot.py +++ b/bot.py @@ -23,6 +23,7 @@ Je suis TuxBot, le bot qui vit de l'OpenSource ! ;) l_extensions = [ 'cogs.basics', + #'cogs.test', 'cogs.admin', 'cogs.funs', 'cogs.utility', @@ -55,9 +56,9 @@ bot = commands.Bot(command_prefix=prefix, description=description, pm_help=None, @bot.event async def on_command_error(error, ctx): if isinstance(error, commands.NoPrivateMessage): - await bot.send_message(ctx.message.author, 'This command cannot be used in private messages.') + await bot.send_message(ctx.message.author, 'Cette commande ne peut pas être utilisée en message privée.') elif isinstance(error, commands.DisabledCommand): - await bot.send_message(ctx.message.author, 'Sorry. This command is disabled and cannot be used.') + await bot.send_message(ctx.message.author, 'Désoler mais cette commande est désactivé, elle ne peut donc pas être utilisée.') elif isinstance(error, commands.CommandInvokeError): print('In {0.command.qualified_name}:'.format(ctx), file=sys.stderr) traceback.print_tb(error.original.__traceback__) @@ -68,7 +69,7 @@ async def on_ready(): print('---------------------') print('Logged in as :') print('Username: ' + bot.user.name) - print('ID: ' + bot.user.id) + print('ID: ' + str(bot.user.id)) print('---------------------') await bot.change_presence(game=discord.Game(name="Manger des pommes ! .help !"), status=discord.Status("dnd"), afk=False) if not hasattr(bot, 'uptime'): @@ -83,7 +84,10 @@ async def on_message(message): if message.author.bot: return - await bot.process_commands(message) + try: + await bot.process_commands(message) + except Exception as e: + print('Hé merde, : \n {}: {} \n \n'.format(type(e).__name__, e)) @bot.command(pass_context=True, hidden=True) @checks.is_owner() @@ -94,15 +98,23 @@ async def do(ctx, times : int, *, command): for i in range(times): await bot.process_commands(msg) - -## GITHUB CMD ## -@bot.command() -async def github(): +@bot.command(pass_context=True) +async def github(ctx): """Pour voir mon code""" text = "How tu veux voir mon repos Github pour me disséquer ? Pas de soucis ! Je suis un Bot, je ne ressens pas la douleur !\n https://github.com/outout14/tuxbot-bot" em = discord.Embed(title='Repos TuxBot-Bot', description=text, colour=0xE9D460) em.set_author(name='Outout', icon_url="https://avatars0.githubusercontent.com/u/14958554?v=3&s=400") - await bot.say(embed=em) + await ctx.send(embed=em) + +async def on_command_error(self, ctx, error): + if isinstance(error, commands.NoPrivateMessage): + await ctx.author.send('Cette commande ne peut pas être utilisée en message privée.') + elif isinstance(error, commands.DisabledCommand): + await ctx.author.send('Désoler mais cette commande est désactivé, elle ne peut donc pas être utilisée.') + elif isinstance(error, commands.CommandInvokeError): + print(f'In {ctx.command.qualified_name}:', file=sys.stderr) + traceback.print_tb(error.original.__traceback__) + print(f'{error.original.__class__.__name__}: {error.original}', file=sys.stderr) ## LOAD ## if __name__ == '__main__': diff --git a/cogs/admin.py b/cogs/admin.py index 2ae1d30..790bbf1 100755 --- a/cogs/admin.py +++ b/cogs/admin.py @@ -5,6 +5,8 @@ import time import discord from .utils import checks +import requests + class Admin: """Commandes secrètes d'administration.""" @@ -12,56 +14,92 @@ class Admin: self.bot = bot @checks.is_owner() - @commands.command() - async def unload(self, module: str): + @commands.command(name='unload_cog', hidden=True) + async def _unload(self, ctx, module: str): """Unloads a module.""" try: - self.bot.unload_extension(module) + self.bot.unload_extension("cogs."+module) except Exception as e: - await self.bot.say('\N{PISTOL}') - await self.bot.say('{}: {}'.format(type(e).__name__, e)) + await ctx.send('\N{PISTOL}') + await ctx.send('{}: {}'.format(type(e).__name__, e)) else: - await self.bot.say('\N{OK HAND SIGN}') + await ctx.send('\N{OK HAND SIGN}') + print("cog : " + str(module) + " activé") + + """--------------------------------------------------------------------------------------------------------------------------""" + + @checks.is_owner() + @commands.command(name='load_cog', hidden=True) + async def _load(self, ctx, module: str): + """Unloads a module.""" + try: + self.bot.load_extension("cogs."+module) + except Exception as e: + await ctx.send('\N{PISTOL}') + await ctx.send('{}: {}'.format(type(e).__name__, e)) + else: + await ctx.send('\N{OK HAND SIGN}') + print("cog : " + str(module) + " desactivé") + + """--------------------------------------------------------------------------------------------------------------------------""" @checks.is_owner() @commands.command(name='reload_cog', hidden=True) - async def _reload(self, *, module: str): + async def _reload(self, ctx, *, module: str): """Reloads a module.""" try: - self.bot.unload_extension(module) - self.bot.load_extension(module) - await self.bot.say("Nice !") + self.bot.unload_extension("cogs."+module) + self.bot.load_extension("cogs."+module) + await ctx.send("Je te reload ca") except Exception as e: #TODO : A virer dans l'event on_error - await self.bot.say(':( Erreur :') - await self.bot.say('{}: {}'.format(type(e).__name__, e)) + await ctx.send(':( Erreur :') + await ctx.send('{}: {}'.format(type(e).__name__, e)) else: - await self.bot.say('\N{OK HAND SIGN}') + await ctx.send('\N{OK HAND SIGN}') + print("cog : " + str(module) + " relancé") + + """--------------------------------------------------------------------------------------------------------------------------""" @checks.is_owner() @commands.command(name='clear', pass_context=True, hidden=True) async def _clear(self, ctx, number: int): - try: - number = number + 1 - await self.bot.purge_from(ctx.message.channel, limit=number) - await self.bot.say("Hello World !") - except Exception as e: #TODO : A virer dans l'event on_error - await self.bot.say(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) + + await ctx.message.delete() + if number < 1000: + async for message in ctx.message.channel.history(limit=number): + try: + await message.delete() + except Exception as e: #TODO : A virer dans l'event on_error + await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) + await ctx.send("Hop voila j'ai viré des messages! Hello World") + print(str(number)+" messages ont été supprimés") + else: + await ctx.send('Trop de messages, entre un nombre < 1000') + + """--------------------------------------------------------------------------------------------------------------------------""" @checks.is_owner() @commands.command(name='say', pass_context=True, hidden=True) - async def _say(self, ctx, *dire:str): + async def _say(self, ctx, *direuh:str): try: - await self.bot.say(dire) - await self.bot.delete_message(ctx.message) + dire = ctx.message.content.split("say ") + await ctx.message.delete() + await ctx.send(dire[1]) except Exception as e: #TODO : A virer dans l'event on_error - await self.bot.say(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) + await ctx.send(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e)) + + """--------------------------------------------------------------------------------------------------------------------------""" @checks.is_owner() @commands.command(pass_context=True, hidden=True) - async def _clearterm(self): + async def _clearterm(self, ctx): clear = "\n" * 100 print(clear) - await self.bot.say(":ok_hand: It's good") + await ctx.send(":ok_hand: It's good") + + """--------------------------------------------------------------------------------------------------------------------------""" + + def setup(bot): bot.add_cog(Admin(bot)) diff --git a/cogs/basics.py b/cogs/basics.py index 697c08a..60831ff 100755 --- a/cogs/basics.py +++ b/cogs/basics.py @@ -7,36 +7,50 @@ import discord import platform, socket import os +import wikipedia, bs4 + class General: """Commandes générales.""" def __init__(self, bot): self.bot = bot - ##PING## @commands.command() - async def ping(self): - """Ping le bot""" - await self.bot.say(":ping_pong: Pong !") + async def ping(self, ctx): + t1 = time.perf_counter() + await ctx.trigger_typing() + t2 = time.perf_counter() + + result = round((t2-t1)*1000) + + if int(result) >=200: + em = discord.Embed(title="Ping : " + str(result) + "ms", description="... c'est quoi ce ping !", colour=0xFF1111) + await ctx.send(embed=em) + elif int(result) > 100 and int(result) < 200: + em = discord.Embed(title="Ping : " + str(result) + "ms", description="Ca va, ça peut aller, mais j'ai l'impression d'avoir 40 ans !", colour=0xFFA500) + await ctx.send(embed=em) + elif int(result) <= 100: + em = discord.Embed(title="Ping : " + str(result) + "ms", description="Wow c'te vitesse de réaction, je m'épate moi-même !",colour=0x11FF11) + await ctx.send(embed=em) ##INFO## @commands.command() - async def info(self): + async def info(self, ctx): """Affiches des informations sur le bot""" text = open('texts/info.md').read() os_info = str(platform.system()) + " / " + str(platform.release()) em = discord.Embed(title='Informations sur TuxBot', description=text.format(os_info, platform.python_version(), socket.gethostname(), discord.__version__), colour=0x89C4F9) em.set_footer(text=os.getcwd() + "/bot.py") - await self.bot.say(embed=em) + await ctx.send(embed=em) ## HELP PLZ ## @commands.command() - async def help(self): + async def help(self, ctx): """Affiches l'aide du bot""" text = open('texts/help.md').read() em = discord.Embed(title='Commandes de TuxBot', description=text, colour=0x89C4F9) - await self.bot.say(embed=em) + await ctx.send(embed=em) def setup(bot): bot.add_cog(General(bot)) diff --git a/cogs/ci.py b/cogs/ci.py index 0164dc4..3f668ce 100755 --- a/cogs/ci.py +++ b/cogs/ci.py @@ -7,6 +7,12 @@ import platform, socket import os import sqlite3 +import time +import datetime, pytz + +from datetime import date +import calendar + #### SQL ##### conn = sqlite3.connect('tuxbot.db') #Connexion SQL @@ -39,7 +45,7 @@ class Identity: if ctx.invoked_subcommand is None: text = open('texts/ci-info.md').read() em = discord.Embed(title='Commandes de carte d\'identité de TuxBot', description=text, colour=0x89C4F9) - await self.bot.say(embed=em) + await ctx.send(embed=em) @_ci.command(pass_context=True, name="show") async def ci_test(self, ctx, args : discord.Member): @@ -50,11 +56,11 @@ class Identity: else: return var - cursor.execute("""SELECT userid, username, useravatar, userbirth, cidate, cibureau, os, config, pays FROM users WHERE userid=?""",(args.id,)) + cursor.execute("""SELECT userid, username, useravatar, userbirth, cidate, cibureau, os, config, pays, id FROM users WHERE userid=?""",(args.id,)) result = cursor.fetchone() if not result: - await self.bot.say(ctx.message.author.mention + "> :x: Désolé mais {} est sans papier !".format(args.mention)) + await ctx.send(ctx.message.author.mention + "> :x: Désolé mais {} est sans papier !".format(args.mention)) else: try: @@ -68,37 +74,57 @@ class Identity: embed.add_field(name="Configuration Système : ", value=isexist(result[7]), inline=True) embed.add_field(name="Date de naissance : ", value=userbirth[0], inline=True) embed.add_field(name="Pays : ", value=isexist(result[8]), inline=True) + embed.add_field(name="Profil sur le web : ", value="https://tuxbot.outout.tech/user-{}".format(result[9]), inline=True) embed.set_footer(text="Enregistré dans le bureau {} le {}.".format(result[5], cidate[0])) - await self.bot.say(embed=embed) + await ctx.send(embed=embed) except: - await self.bot.say(ctx.message.author.mention + "> :x: Désolé mais la carte d'identité de {0} est trop longue de ce fait je ne peux te l'envoyer, essaye de l'aléger, {0} :wink: !".format(args.mention)) + await ctx.send(ctx.message.author.mention + "> :x: Désolé mais la carte d'identité de {0} est trop longue de ce fait je ne peux te l'envoyer, essaye de l'aléger, {0} :wink: !".format(args.mention)) @_ci.command(pass_context=True, name="register") async def ci_register(self, ctx): cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) existansw = cursor.fetchone() if existansw != None: - await self.bot.say("Mais tu as déja une carte d'identité ! u_u") + await ctx.send("Mais tu as déja une carte d'identité ! u_u") else: - cursor.execute("""INSERT INTO users(userid, username, useravatar, userbirth, cidate, cibureau) VALUES(?, ?, ?, ?, ?, ?)""", (ctx.message.author.id, ctx.message.author.name, ctx.message.author.avatar_url, ctx.message.author.created_at, ctx.message.timestamp, ctx.message.server.name)) - conn.commit() - await self.bot.say(":clap: Bievenue à toi {} dans le communisme {} ! Fait ``.ci`` pour plus d'informations !".format(ctx.message.author.name, ctx.message.server.name)) + date = datetime.datetime.now() - @_ci.command(pass_context=True, name="upimage") + nd = str(date.day) + nd += "-" + nd += str(date.month) + nd += "-" + nd += str(date.year) + + cursor.execute("""INSERT INTO users(userid, username, useravatar, userbirth, cidate, cibureau) VALUES(?, ?, ?, ?, ?, ?)""", (ctx.message.author.id, ctx.message.author.name, ctx.message.author.avatar_url, ctx.message.author.created_at, nd, str(ctx.message.guild.name))) + conn.commit() + await ctx.send(":clap: Bievenue à toi {} dans le communisme {} ! Fait ``.ci`` pour plus d'informations !".format(ctx.message.author.name, str(ctx.message.guild.name))) + + @_ci.command(pass_context=True, name="delete") + async def ci_delete(self, ctx): + cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) + existansw = cursor.fetchone() + if existansw != None: + cursor.execute("""DELETE FROM users WHERE userid =?""", (ctx.message.author.id,)) + await ctx.send("Tu es maintenant sans papiers !") + else: + await ctx.send("Déja enregistre ta carte d'identité avant de la supprimer u_u (après c'est pas logique...)") + + @_ci.command(pass_context=True, name="update") async def ci_image(self, ctx): try: cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,)) existansw = cursor.fetchone() if existansw != None: - cursor.execute("""UPDATE users SET useravatar = ? WHERE userid = ?""", (ctx.message.author.avatar_url, ctx.message.author.id)) + cursor.execute("""UPDATE users SET useravatar = ?, username = ?, cibureau = ? WHERE userid = ?""", (ctx.message.author.avatar_url, ctx.message.author.name, str(ctx.message.guild), ctx.message.author.id)) conn.commit() - await self.bot.say(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour; Sympa ton nouvel avatar :wink: !") + await ctx.send(ctx.message.author.mention + "> Tu viens, en quelques sortes, de renaitre !") else: - await self.bot.say(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + except Exception as e: #TODO : A virer dans l'event on_error - await self.bot.say(':( Erreur veuillez contacter votre administrateur :') - await self.bot.say('{}: {}'.format(type(e).__name__, e)) + await ctx.send(':( Erreur veuillez contacter votre administrateur :') + await ctx.send('{}: {}'.format(type(e).__name__, e)) @_ci.command(pass_context=True, name="setconfig") async def ci_setconfig(self, ctx, args_): @@ -111,11 +137,11 @@ class Identity: if existansw != None: cursor.execute("""UPDATE users SET config = ? WHERE userid = ?""", (args, ctx.message.author.id)) conn.commit() - await self.bot.say(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") + await ctx.send(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") else: - await self.bot.say(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") except: - await self.bot.say(ctx.message.author.mention + "> :x: Il manque un paramètre !") + await ctx.send(ctx.message.author.mention + "> :x: Il manque un paramètre !") @_ci.command(pass_context=True, name="setos") async def ci_setos(self, ctx, args_): @@ -128,11 +154,11 @@ class Identity: if existansw != None: cursor.execute("""UPDATE users SET os = ? WHERE userid = ?""", (args, ctx.message.author.id)) conn.commit() - await self.bot.say(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") + await ctx.send(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") else: - await self.bot.say(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") except: - await self.bot.say(ctx.message.author.mention + "> :x: Il manque un paramètre !") + await ctx.send(ctx.message.author.mention + "> :x: Il manque un paramètre !") @_ci.command(pass_context=True, name="setcountry") async def ci_setcountry(self, ctx, args): @@ -142,9 +168,9 @@ class Identity: if existansw != None: cursor.execute("""UPDATE users SET pays = ? WHERE userid = ?""", (args, ctx.message.author.id)) conn.commit() - await self.bot.say(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") + await ctx.send(ctx.message.author.mention + "> :ok_hand: Carte d'identité mise à jour !") else: - await self.bot.say(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") + await ctx.send(ctx.message.author.mention + "> :x: Veuillez enregistrer votre carte d'identité pour commencer !") @_ci.command(pass_context=True, name="list") async def ci_list(self, ctx): @@ -154,9 +180,9 @@ class Identity: try: for row in rows: msg = msg + '{0} : {1} \n'.format(row[0], row[1]) - await self.bot.say(msg) + await ctx.send(msg) except: - await self.bot.say(":x: Pas d'entrés") + await ctx.send(":x: Pas d'entrés") def setup(bot): bot.add_cog(Identity(bot)) diff --git a/cogs/funs.py b/cogs/funs.py index 9c86bf7..f93d465 100755 --- a/cogs/funs.py +++ b/cogs/funs.py @@ -16,21 +16,22 @@ class Funs: @commands.command() - async def avatar(self, user : discord.Member): + async def avatar(self, ctx, user : discord.Member): """Récuperer l'avatar de ...""" embed = discord.Embed(title="Avatar de : " + user.name, url=user.avatar_url, description="[Voir en plus grand]({})".format(user.avatar_url)) embed.set_thumbnail(url=user.avatar_url) - await self.bot.say(embed=embed) + await ctx.send(embed=embed) @commands.command(pass_context=True) - async def poke(self, user : discord.Member): + async def poke(self, ctx, user : discord.Member): """Poke quelqu'un""" - await self.bot.say(":clap: Hey {0} tu t'es fait poker par {1}.".format(user.mention, ctx.message.author)) + await ctx.send(":clap: Hey {0} tu t'es fait poker par {1} !".format(user.mention, ctx.message.author.name)) + await ctx.message.delete() @commands.command() - async def btcprice(self): + async def btcprice(self, ctx): """Le prix du BTC""" - loading = await self.bot.say("_réfléchis..._") + loading = await ctx.send("_réfléchis..._") try: with urllib.request.urlopen("http://api.coindesk.com/v1/bpi/currentprice/EUR.json") as url: data = json.loads(url.read().decode()) @@ -40,26 +41,26 @@ class Funs: btc = 1 if btc == 1: - await self.bot.say("Impossible d'accèder à l'API coindesk.com, veuillez réessayer ultérieurment !") + await ctx.send("Impossible d'accèder à l'API coindesk.com, veuillez réessayer ultérieurment !") else: - await self.bot.edit_message(loading, "Un bitcoin est égal à : " + btc[0] + " €") + await loading.edit(content="Un bitcoin est égal à : " + btc[0] + " €") @commands.command() - async def joke(self): + async def joke(self, ctx): """Print a random joke in a json file""" with open('texts/jokes.json') as js: jk = json.load(js) - clef = str(random.randint(1,12)) + clef = str(random.randint(1,13)) joke = jk["{}".format(clef)] embed = discord.Embed(title="Blague _{}_ : ".format(clef), description=joke['content'], colour=0x03C9A9) embed.set_footer(text="Par " + joke['author']) embed.set_thumbnail(url='https://outout.tech/tuxbot/blobjoy.png') - await self.bot.say(embed=embed) + await ctx.send(embed=embed) @commands.command() - async def ethylotest(self): + async def ethylotest(self, ctx): """Ethylotest simulator 2018""" results_poulet = ["Désolé mais mon ethylotest est sous Windows Vista, merci de patienter...", "_(ethylotest)_ ``Une erreur est survenue. Windows cherche une solution à se problème...``", "Mais j'l'ai foutu où ce p*** d'ethylotest de m*** bordel fait ch*** tab***", "C'est pas possible z'avez cassé l'ethylotest !"] results_client = ["D'accord, il n'y a pas de problème à cela je suis complètement clean", "Bien sur si c'est votre devoir !", "Suce bi** !", "J'ai l'air d'être bourré ?", "_laissez moi prendre un bonbon à la menthe..._"] @@ -67,14 +68,14 @@ class Funs: result_p = random.choice(results_poulet) result_c = random.choice(results_client) - await self.bot.say(":oncoming_police_car: Bonjour bonjour, controle d'alcoolémie !") + await ctx.send(":oncoming_police_car: Bonjour bonjour, controle d'alcoolémie !") await asyncio.sleep(0.5) - await self.bot.say(":man: " + result_c) + await ctx.send(":man: " + result_c) await asyncio.sleep(1) - await self.bot.say(":police_car: " + result_p) + await ctx.send(":police_car: " + result_p) @commands.command() - async def coin(self): + async def coin(self, ctx): """Coin flip simulator 2025""" starts_msg = ["Je lance la pièce !", "C'est parti !", "C'est une pièce d'un cent faut pas la perdre", "C'est une pièce d'un euro faut pas la perdre", "Je lance !"] results_coin = ["{0} pile", "{0} face", "{1} Heu c'est quoi pile c'est quoi face enfaite ?", "{1} Oh shit, je crois que je l'ai perdue", "{1} Et bim je te vol ta pièce !", "{0} Oh une erreur d'impression il n'y a ni pile ni face !"] @@ -82,12 +83,12 @@ class Funs: start = random.choice(starts_msg) result = random.choice(results_coin) - await self.bot.say(start) + await ctx.send(start) await asyncio.sleep(0.6) - await self.bot.say(result.format(":moneybag: Et la pièce retombe sur ...", ":robot:")) + await ctx.send(result.format(":moneybag: Et la pièce retombe sur ...", ":robot:")) @commands.command() - async def pokemon(self): + async def pokemon(self, ctx): """Random pokemon fight""" with open('texts/pokemons.json') as js: jk = json.load(js) @@ -103,20 +104,20 @@ class Funs: except: winer = poke1 - await self.bot.say(":flag_white: **Le combat commence !**") + await ctx.send(":flag_white: **Le combat commence !**") await asyncio.sleep(1) - await self.bot.say(":loudspeaker: Les concurants sont {} contre {} ! Bonne chance à eux !".format(poke1["Name"], poke2["Name"])) + await ctx.send(":loudspeaker: Les concurants sont {} contre {} ! Bonne chance à eux !".format(poke1["Name"], poke2["Name"])) await asyncio.sleep(0.5) - await self.bot.say(":boom: {} commence et utilise {}".format(poke1["Name"], poke1["Fast Attack(s)"][0]["Name"])) + await ctx.send(":boom: {} commence et utilise {}".format(poke1["Name"], poke1["Fast Attack(s)"][0]["Name"])) await asyncio.sleep(1) - await self.bot.say(":dash: {} réplique avec {}".format(poke2["Name"], poke2["Fast Attack(s)"][0]["Name"])) + await ctx.send(":dash: {} réplique avec {}".format(poke2["Name"], poke2["Fast Attack(s)"][0]["Name"])) await asyncio.sleep(1.2) - await self.bot.say("_le combat continue de se dérouler..._") + await ctx.send("_le combat continue de se dérouler..._") await asyncio.sleep(1.5) - await self.bot.say(":trophy: Le gagnant est **{}** !".format(winer["Name"])) + await ctx.send(":trophy: Le gagnant est **{}** !".format(winer["Name"])) @commands.command() - async def randomcat(self): + async def randomcat(self, ctx): """Display a random cat""" r = requests.get('http://random.cat/meow.php') @@ -124,7 +125,7 @@ class Funs: embed = discord.Embed(title="Meow", description="[Voir le chat plus grand]({})".format(cat), colour=0x03C9A9) embed.set_thumbnail(url=cat) embed.set_author(name="Random.cat", url='https://random.cat/', icon_url='http://outout.tech/tuxbot/nyancat2.gif') - await self.bot.say(embed=embed) + await ctx.send(embed=embed) diff --git a/cogs/search.py b/cogs/search.py index 93c3a2f..8952358 100755 --- a/cogs/search.py +++ b/cogs/search.py @@ -19,30 +19,28 @@ class Search: if ctx.invoked_subcommand is None: text = open('texts/search.md').read() em = discord.Embed(title='Commandes de search TuxBot', description=text, colour=0x89C4F9) - await self.bot.say(embed=em) + await ctx.send(embed=em) @_search.command(pass_context=True, name="docubuntu") async def search_docubuntu(self, ctx, args): - await self.bot.send_typing(ctx.message.channel) - attends = await self.bot.say("_Je te cherche ça {} !_".format(ctx.message.author.mention)) + attends = await ctx.send("_Je te cherche ça {} !_".format(ctx.message.author.mention)) html = urllib.request.urlopen("https://doc.ubuntu-fr.org/" + args).read() if "avez suivi un lien" in str(html): - await self.bot.edit_message(attends, ":sob: Nooooon ! Cette page n'existe pas, mais tu peux toujours la créer : https://doc.ubuntu-fr.org/"+ args) + await attends.edit(content=":sob: Nooooon ! Cette page n'existe pas, mais tu peux toujours la créer : https://doc.ubuntu-fr.org/"+ args) else: - await self.bot.delete_message(attends) + await attends.delete() embed = discord.Embed(description="Voila j'ai trouvé ! Voici la page ramenant à votre recherche, toujours aussi bien rédigée :wink: : https://doc.ubuntu-fr.org/" + args, url='http://doc.ubuntu-fr.org/') embed.set_author(name="DocUbuntu-Fr", url='http://doc.ubuntu-fr.org/', icon_url='http://outout.tech/tuxbot/ubuntu.png') embed.set_thumbnail(url='http://outout.tech/tuxbot/ubuntu.png') embed.set_footer(text="Merci à ceux qui ont pris le temps d'écrire cette documentation") - await self.bot.say(embed=embed) + await ctx.send(embed=embed) @_search.command(pass_context=True, name="aur") async def search_aur(self, ctx, args): - await self.bot.send_typing(ctx.message.channel) - attends = await self.bot.say("_Je te cherche ça {} !_".format(ctx.message.author.mention)) + attends = await ctx.send("_Je te cherche ça {} !_".format(ctx.message.author.mention)) erreur = 0 try: html = urllib.request.urlopen("https://aur.archlinux.org/packages/" + args).read() @@ -50,73 +48,81 @@ class Search: erreur = 1 if erreur == 1: - await self.bot.delete_message(attends) + await attends.delete() embed = discord.Embed(description=":sob: Je n'ai pas trouvé le packet mais j'ai lancé une petite recherche, tu y trouveras peut être ton bonheur ? https://aur.archlinux.org/packages/?K=" + args,url='https://aur.archlinux.org/') embed.set_author(name="Aur.archlinux", url='https://aur.archlinux.org/', icon_url='http://outout.tech/tuxbot/arch.png') embed.set_thumbnail(url='http://outout.tech/tuxbot/arch.png') embed.set_footer(text="Pff même pas trouvé !") - await self.bot.say(embed=embed) + await ctx.send(embed=embed) else: - await self.bot.delete_message(attends) - embed = discord.Embed(description="Et voila, j'ai trouvé la page sur le packet : https://aur.archlinux.org/packages/{0} ! \n Ca te dit un petit ``yaourt -S {0}`` ?".format(args), url='https://aur.archlinux.org/') - embed.set_author(name="Aur.archlinux", url='https://aur.archlinux.org/', icon_url='http://outout.tech/tuxbot/arch.png') - embed.set_thumbnail(url='http://outout.tech/tuxbot/arch.png') - embed.set_footer(text="C'est vrai que Aur est mieux qu'APT ^^") - await self.bot.say(embed=embed) + await attends.delete() + embed = discord.Embed(description="Et voila, j'ai trouvé la page sur le packet : https://aur.archlinux.org/packages/{0} ! \n Ca te dit un petit ``pacaur -S {0}`` ?".format(args), url='https://aur.archlinux.org/') + embed.set_author(name="Aur.archlinux", url='https://aur.archlinux.org/', icon_url='http://outout.tech/tuxbot/arch.png') + embed.set_thumbnail(url='http://outout.tech/tuxbot/arch.png') + embed.set_footer(text="C'est vrai que pacman et pacaur sont mieux qu'APT ^^") + await ctx.send(embed=embed) @_search.command(pass_context=True, name="wikipedia") - async def search_wikipedia(self, ctx, args): + async def search_wikipedia(self, ctx: commands.Context, args): """Fait une recherche sur wikipd""" - try: # C'est quoi ce try-except de la mort ? - wait = await self.bot.say("_Je cherche..._") - results = wikipedia.search(args) - nbmr = 0 - msg = "" - for value in results: - nbmr = nbmr + 1 - msg = msg + "**{}**: {} \n".format(str(nbmr), value) + wait = await ctx.send("_Je cherche..._") + results = wikipedia.search(args) + nbmr = 0 + mmssgg = "" - em = discord.Embed(title='Résultats de : ' + args, description = msg, colour=0x4ECDC4) + for value in results: + nbmr = nbmr + 1 + mmssgg = mmssgg + "**{}**: {} \n".format(str(nbmr), value) + + em = discord.Embed(title='Résultats de : ' + args, description = mmssgg, colour=0x4ECDC4) + em.set_thumbnail(url = "https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png") + await wait.delete() + + sending = ["1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟"] + + def check(reaction, user): + return user == ctx.author and reaction.emoji in sending and reaction.message.id == msg.id + + async def waiter(future: asyncio.Future): + reaction, user = await self.bot.wait_for('reaction_add', check=check) + future.set_result(reaction.emoji) + + emoji = asyncio.Future() + self.bot.loop.create_task(waiter(emoji)) + + msg = await ctx.send(embed=em) + for e in sending: + await msg.add_reaction(e) + if emoji.done(): + break + + while not emoji.done(): + await asyncio.sleep(0.1) + + sPage = int(sending.index(emoji.result())) + + args_ = results[sPage] + + try: + await msg.delete() + await ctx.trigger_typing() + wait = await ctx.send(ctx.message.author.mention + " ah ok sympa cette recherche, je l'effectue de suite !") + wp = wikipedia.page(args_) + wp_contenu = wp.summary[:200] + "..." + em = discord.Embed(title='Wikipedia : ' + wp.title, description = "{} \n_Lien_ : {} ".format(wp_contenu, wp.url), colour=0x9B59B6) + em.set_author(name="Wikipedia", url='http://wikipedia.org', icon_url='https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png') em.set_thumbnail(url = "https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png") - await self.bot.delete_message(wait) - final = await self.bot.say(embed=em) + em.set_footer(text="Merci à eux de nous fournir une encyclopédie libre !") + await wait.delete() + await ctx.send(embed=em) - list_emojis = ["1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟"] + except wikipedia.exceptions.PageError: #TODO : A virer dans l'event on_error + await ctx.send(":open_mouth: Une **erreur interne** est survenue, si cela ce reproduit contactez votre administrateur ou faites une Issue sur ``github`` !") - for emoji in list_emojis: - await self.bot.add_reaction(final, emoji) - res = await self.bot.wait_for_reaction(message=final, user=ctx.message.author) - - for emoji in list_emojis: - num_emoji = list_emojis.index(emoji) - if res.reaction.emoji == emoji: - args_ = results[num_emoji] - - try: - await self.bot.delete_message(final) - await self.bot.send_typing(ctx.message.channel) - wait = await self.bot.say(ctx.message.author.mention + " ah ok sympa cette recherche, je l'effectue de suite !") - wp = wikipedia.page(args_) - wp_contenu = wp.summary[:200] + "..." - em = discord.Embed(title='Wikipedia : ' + wp.title, description = "{} \n_Lien_ : {} ".format(wp_contenu, wp.url), colour=0x9B59B6) - em.set_author(name="Wikipedia", url='http://wikipedia.org', icon_url='https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png') - em.set_thumbnail(url = "https://upload.wikimedia.org/wikipedia/commons/2/26/Paullusmagnus-logo_%28large%29.png") - em.set_footer(text="Merci à eux de nous fournir une encyclopédie libre !") - await self.bot.delete_message(wait) - await self.bot.say(embed=em) - - except wikipedia.exceptions.PageError: #TODO : A virer dans l'event on_error - await self.bot.say(":open_mouth: Une **erreur interne** est survenue, si cela ce reproduit contactez votre administrateur ou faites une Issue sur ``github`` !") - except UnboundLocalError: - await self.bot.say(":interrobang: Veuillez choisir une réaction valide !") - except DisambiguationError: #TODO : A virer dans l'event on_error - await self.bot.say(":open_mouth: Une **erreur interne** est survenue, si cela ce reproduit contactez votre administrateur ou faites une Issue sur ``github`` !") - except IndexError: - await self.bot.say(" :interrobang: Veuillez entrer un terme de recherche !") def setup(bot): bot.add_cog(Search(bot)) diff --git a/cogs/utility.py b/cogs/utility.py index a6b35dd..b7bb422 100755 --- a/cogs/utility.py +++ b/cogs/utility.py @@ -8,6 +8,11 @@ import discord import urllib.request, json import datetime, pytz +from datetime import date +import calendar +import requests + + class Utility: """Commandes utilitaires.""" @@ -15,7 +20,7 @@ class Utility: self.bot = bot @commands.command() - async def clock(self, args): + async def clock(self, ctx, args): """Display hour in a country""" args = args.upper() then = datetime.datetime.now(pytz.utc) @@ -80,19 +85,21 @@ class Utility: if args == "LIST": text = open('texts/clocks.md').read() em = discord.Embed(title='Liste des Horloges', description=text, colour=0xEEEEEE) - await self.bot.say(embed=em) + await ctx.send(embed=em) else: tt = utc.strftime(form) em = discord.Embed(title='Heure à ' + args.title(), description="A [{}]({}) {}, Il est **{}** ! \n {} \n _source des images et du texte : [Wikimedia foundation](http://commons.wikimedia.org/)_".format(str(args), site, str(country), str(tt), str(description)), colour=0xEEEEEE) em.set_thumbnail(url = img) - await self.bot.say(embed=em) + await ctx.send(embed=em) except UnboundLocalError: - await self.bot.say("[**Erreur**] Ville inconnue, faites ``.clock list`` pour obtenir la liste des villes") + await ctx.send("[**Erreur**] Ville inconnue, faites ``.clock list`` pour obtenir la liste des villes") except IndexError: - await self.bot.say("[**Erreur**] Ville inconnue, faites ``.clock list`` pour obtenir la liste des villes") + await ctx.send("[**Erreur**] Ville inconnue, faites ``.clock list`` pour obtenir la liste des villes") + + """--------------------------------------------------------------------------------------------------------------------------""" @commands.command() - async def ytdiscover(self): + async def ytdiscover(self, ctx): """Random youtube channel""" with open('texts/ytb.json') as js: ytb = json.load(js) @@ -103,7 +110,9 @@ class Utility: embed = discord.Embed(title=chaine['name'], url=chaine['url'], description="**{}**, {} \n[Je veux voir ça]({})".format(chaine['name'], chaine['desc'], chaine['url'])) embed.set_thumbnail(url='https://outout.tech/tuxbot/yt.png') - await self.bot.say(embed=embed) + await ctx.send(embed=embed) + + """--------------------------------------------------------------------------------------------------------------------------""" @commands.command(pass_context=True) async def afk(self, ctx): @@ -111,7 +120,9 @@ class Utility: msgs = ["s'absente de discord quelques instants", "se casse de son pc", "va sortir son chien", "reviens bientôt", "va nourrir son cochon", "va manger des cookies", "va manger de la poutine", "va faire caca", "va faire pipi"] msg = random.choice(msgs) - await self.bot.say("**{}** {}...".format(ctx.message.author.mention, msg)) + await ctx.send("**{}** {}...".format(ctx.message.author.mention, msg)) + + """--------------------------------------------------------------------------------------------------------------------------""" @commands.command(pass_context=True) async def back(self, ctx): @@ -119,8 +130,113 @@ class Utility: msgs = ["a réssuscité", "est de nouveau parmi nous", "a fini de faire caca", "a fini d'urine", "n'est plus mort", "est de nouveau sur son PC", "a fini de manger sa poutine", "a fini de danser", "s'est réveillé", "est de retour dans ce monde cruel"] msg = random.choice(msgs) - await self.bot.say("**{}** {} !".format(ctx.message.author.mention, msg)) + await ctx.send("**{}** {} !".format(ctx.message.author.mention, msg)) + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command(pass_context=True) + async def sondage(self, ctx, *, msg): + """Create a poll using reactions. >help rpoll for more information. + >rpoll | | - Create a poll. You may use as many answers as you want, placing a pipe | symbol in between them. + Example: + >rpoll What is your favorite anime? | Steins;Gate | Naruto | Attack on Titan | Shrek + You can also use the "time" flag to set the amount of time in seconds the poll will last for. + Example: + >rpoll What time is it? | HAMMER TIME! | SHOWTIME! | time=10 + """ + await ctx.message.delete() + options = msg.split(" | ") + time = [x for x in options if x.startswith("time=")] + if time: + time = time[0] + if time: + options.remove(time) + if len(options) <= 1: + raise commands.errors.MissingRequiredArgument + if len(options) >= 11: + return await ctx.send("Vous ne pouvez mettre que 9 options de réponse ou moins.") + if time: + time = int(time.strip("time=")) + else: + time = 0 + emoji = ['1⃣', '2⃣', '3⃣', '4⃣', '5⃣', '6⃣', '7⃣', '8⃣', '9⃣'] + to_react = [] + confirmation_msg = "**{}?**:\n\n".format(options[0].rstrip("?")) + for idx, option in enumerate(options[1:]): + confirmation_msg += "{} - {}\n".format(emoji[idx], option) + to_react.append(emoji[idx]) + confirmation_msg += "*Sondage proposé par* "+str(ctx.message.author.mention) + if time == 0: + confirmation_msg += "" + else: + confirmation_msg += "\n\nVous avez {} secondes pour voter!".format(time) + poll_msg = await ctx.send(confirmation_msg) + for emote in to_react: + await poll_msg.add_reaction(emote) + + if time != 0: + await asyncio.sleep(time) + + if time != 0: + async for message in ctx.message.channel.history(): + if message.id == poll_msg.id: + poll_msg = message + results = {} + for reaction in poll_msg.reactions: + if reaction.emoji in to_react: + results[reaction.emoji] = reaction.count - 1 + end_msg = "Le sondage est términé. Les résultats sont:\n\n" + for result in results: + end_msg += "{} {} - {} votes\n".format(result, options[emoji.index(result)+1], results[result]) + top_result = max(results, key=lambda key: results[key]) + if len([x for x in results if results[x] == results[top_result]]) > 1: + top_results = [] + for key, value in results.items(): + if value == results[top_result]: + top_results.append(options[emoji.index(key)+1]) + end_msg += "\nLes gagnants sont : {}".format(", ".join(top_results)) + else: + top_result = options[emoji.index(top_result)+1] + end_msg += "\n\"{}\" est le gagnant!".format(top_result) + await ctx.send(end_msg) + + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command(pass_context=True) + async def sondage_aide(self, ctx): + await ctx.message.delete() + + text = open('texts/rpoll.md').read() + em = discord.Embed(title='Aide sur le sondage', description=text, colour=0xEEEEEE) + await ctx.send(embed=em) + + """--------------------------------------------------------------------------------------------------------------------------""" + + @commands.command(name='hastebin', pass_context=True) + async def _hastebin(self, ctx, *, data): + """Poster sur Hastebin.""" + await ctx.message.delete() + + post = requests.post("https://hastebin.com/documents", data=data) + + try: + await ctx.send(str(ctx.message.author.mention)+" message posté avec succes sur :\nhttps://hastebin.com/{}.txt".format(post.json()["key"])) + except json.JSONDecodeError: + await ctx.send("Impossible de poster ce message. L'API doit etre HS.") + + @commands.command(name='test', pass_context=True) + async def test(self, ctx): + + date = datetime.datetime.now() + + nd = str(date.day) + nd += "-" + nd += str(date.month) + nd += "-" + nd += str(date.year) + + await ctx.send(nd) def setup(bot): bot.add_cog(Utility(bot)) diff --git a/cogs/utils/__pycache__/__init__.cpython-35.pyc b/cogs/utils/__pycache__/__init__.cpython-35.pyc deleted file mode 100755 index 56d35d7..0000000 Binary files a/cogs/utils/__pycache__/__init__.cpython-35.pyc and /dev/null differ diff --git a/cogs/utils/__pycache__/checks.cpython-35.pyc b/cogs/utils/__pycache__/checks.cpython-35.pyc deleted file mode 100755 index 7c5f93d..0000000 Binary files a/cogs/utils/__pycache__/checks.cpython-35.pyc and /dev/null differ diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 3785740..5f8fd47 100755 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -3,9 +3,13 @@ import discord.utils from discord.ext import commands -def is_owner_check(message): - owner = message.author.id in ['171685542553976832', '163697401935298560', '88644904112128000', '92619860521005056', '273757386127441920'] ###ID's modo & admin - return owner # Owner of the bot +def is_owner_check(message): # OUTOUT id RICK id L4P1N id GIGA id FLAYOR id ROMAIN id + owner = str(message.author.id) in ['171685542553976832', '163697401935298560', '88644904112128000', '92619860521005056', '273757386127441920', '269156684155453451'] ###ID's modo & admin + rights = str(message.author.top_role.name).upper() in ['ADMIN', 'ADMINISTRATEURS', 'ADMINISTRATEUR', 'MODO', 'MODÉRATEUR', 'MODÉRATEURS', 'MODERATEUR', 'MODERATEURS'] + if rights == True or owner == True: + return True # Owner of the bot + else: + return False def is_owner(warn=True): def check(ctx, warn): @@ -55,4 +59,17 @@ def is_in_servers(*server_ids): return False return server.id in server_ids - return commands.check(predicate) \ No newline at end of file + return commands.check(predicate) + +def embed_perms(message): + try: + check = message.author.permissions_in(message.channel).embed_links + except: + check = True + + return check + +def is_mod(): + async def pred(ctx): + return await check_guild_permissions(ctx, {'manage_guild': True}) + return commands.check(pred) \ No newline at end of file diff --git a/cogs/utils/menu.py b/cogs/utils/menu.py new file mode 100644 index 0000000..ea2c809 --- /dev/null +++ b/cogs/utils/menu.py @@ -0,0 +1,140 @@ +import asyncio + +class Menu: + """An interactive menu class for Discord.""" + + + class Submenu: + """A metaclass of the Menu class.""" + def __init__(self, name, content): + self.content = content + self.leads_to = [] + self.name = name + + def get_text(self): + text = "" + for idx, menu in enumerate(self.leads_to): + text += "[{}] {}\n".format(idx+1, menu.name) + return text + + def get_child(self, child_idx): + try: + return self.leads_to[child_idx] + except IndexError: + raise IndexError("child index out of range") + + def add_child(self, child): + self.leads_to.append(child) + + class InputSubmenu: + """A metaclass of the Menu class for submenu options that take input, instead of prompting the user to pick an option.""" + def __init__(self, name, content, input_function, leads_to): + self.content = content + self.name = name + self.input_function = input_function + self.leads_to = leads_to + + def next_child(self): + return self.leads_to + + class ChoiceSubmenu: + """A metaclass of the Menu class for submenu options for choosing an option from a list.""" + def __init__(self, name, content, options, input_function, leads_to): + self.content = content + self.name = name + self.options = options + self.input_function = input_function + self.leads_to = leads_to + + def next_child(self): + return self.leads_to + + + def __init__(self, main_page): + self.children = [] + self.main = self.Submenu("main", main_page) + + def add_child(self, child): + self.main.add_child(child) + + async def start(self, ctx): + current = self.main + menu_msg = None + while True: + output = "" + + if type(current) == self.Submenu: + if type(current.content) == str: + output += current.content + "\n" + elif callable(current.content): + current.content() + else: + raise TypeError("submenu body is not a str or function") + + if not current.leads_to: + if not menu_msg: + menu_msg = await ctx.send("```" + output + "```") + else: + await menu_msg.edit(content="```" + output + "```") + break + + output += "\n" + current.get_text() + "\n" + output += "Enter a number." + + if not menu_msg: + menu_msg = await ctx.send("```" + output + "```") + else: + await menu_msg.edit(content="```" + output + "```") + + reply = await ctx.bot.wait_for("message", check=lambda m: m.author == ctx.bot.user and m.content.isdigit() and m.channel == ctx.message.channel) + await reply.delete() + + try: + current = current.get_child(int(reply.content) - 1) + except IndexError: + print("Invalid number.") + break + + elif type(current) == self.InputSubmenu: + if type(current.content) == list: + answers = [] + for question in current.content: + await menu_msg.edit(content="```" + question + "\n\nEnter a value." + "```") + reply = await ctx.bot.wait_for("message", check=lambda m: m.author == ctx.bot.user and m.channel == ctx.message.channel) + await reply.delete() + answers.append(reply) + current.input_function(*answers) + else: + await menu_msg.edit(content="```" + current.content + "\n\nEnter a value." + "```") + reply = await ctx.bot.wait_for("message", check=lambda m: m.author == ctx.bot.user and m.channel == ctx.message.channel) + await reply.delete() + current.input_function(reply) + + if not current.leads_to: + break + + current = current.leads_to + + elif type(current) == self.ChoiceSubmenu: + result = "```" + current.content + "\n\n" + if type(current.options) == dict: + indexes = {} + for idx, option in enumerate(current.options): + result += "[{}] {}: {}\n".format(idx+1, option, current.options[option]) + indexes[idx] = option + else: + for idx, option in current.options: + result += "[{}] {}\n".format(idx+1, option) + await menu_msg.edit(content=result + "\nPick an option.```") + reply = await ctx.bot.wait_for("message", check=lambda m: m.author == ctx.bot.user and m.content.isdigit() and m.channel == ctx.message.channel) + await reply.delete() + if type(current.options) == dict: + current.input_function(reply, indexes[int(reply.content)-1]) + else: + current.input_function(reply, current.options[reply-1]) + + if not current.leads_to: + break + + current = current.leads_to + \ No newline at end of file diff --git a/cogs/utils/paginator.py b/cogs/utils/paginator.py index 8914744..8babff3 100755 --- a/cogs/utils/paginator.py +++ b/cogs/utils/paginator.py @@ -15,14 +15,14 @@ class Pages: Parameters ------------ - bot - The bot instance. - message - The message that initiated this session. - entries + ctx: Context + The context of the command. + entries: List[str] A list of entries to paginate. - per_page + per_page: int How many entries show up per page. + show_entry_count: bool + Whether to show an entry count in the footer. Attributes ----------- @@ -33,18 +33,20 @@ class Pages: permissions: discord.Permissions Our permissions for the channel. """ - def __init__(self, bot, *, message, entries, per_page=12): - self.bot = bot + def __init__(self, ctx, *, entries, per_page=12, show_entry_count=True): + self.bot = ctx.bot self.entries = entries - self.message = message - self.author = message.author + self.message = ctx.message + self.channel = ctx.channel + self.author = ctx.author self.per_page = per_page pages, left_over = divmod(len(self.entries), self.per_page) if left_over: pages += 1 self.maximum_pages = pages - self.embed = discord.Embed() + self.embed = discord.Embed(colour=discord.Colour.blurple()) self.paginating = len(entries) > per_page + self.show_entry_count = show_entry_count self.reaction_emojis = [ ('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page), ('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page), @@ -55,15 +57,25 @@ class Pages: ('\N{INFORMATION SOURCE}', self.show_help), ] - server = self.message.server - if server is not None: - self.permissions = self.message.channel.permissions_for(server.me) + if ctx.guild is not None: + self.permissions = self.channel.permissions_for(ctx.guild.me) else: - self.permissions = self.message.channel.permissions_for(self.bot.user) + self.permissions = self.channel.permissions_for(ctx.bot.user) if not self.permissions.embed_links: raise CannotPaginate('Bot does not have embed links permission.') + if not self.permissions.send_messages: + raise CannotPaginate('Bot cannot send messages.') + + if self.paginating: + # verify we can actually use the pagination session + if not self.permissions.add_reactions: + raise CannotPaginate('Bot does not have add reactions permission.') + + if not self.permissions.read_message_history: + raise CannotPaginate('Bot does not have Read Message History permission.') + def get_page(self, page): base = (page - 1) * self.per_page return self.entries[base:base + self.per_page] @@ -72,31 +84,30 @@ class Pages: self.current_page = page entries = self.get_page(page) p = [] - for t in enumerate(entries, 1 + ((page - 1) * self.per_page)): - p.append('%s. %s' % t) + for index, entry in enumerate(entries, 1 + ((page - 1) * self.per_page)): + p.append(f'{index}. {entry}') - self.embed.set_footer(text='Page %s/%s (%s entries)' % (page, self.maximum_pages, len(self.entries))) + if self.maximum_pages > 1: + if self.show_entry_count: + text = f'Page {page}/{self.maximum_pages} ({len(self.entries)} entries)' + else: + text = f'Page {page}/{self.maximum_pages}' + + self.embed.set_footer(text=text) if not self.paginating: self.embed.description = '\n'.join(p) - return await self.bot.send_message(self.message.channel, embed=self.embed) + return await self.channel.send(embed=self.embed) if not first: self.embed.description = '\n'.join(p) - await self.bot.edit_message(self.message, embed=self.embed) + await self.message.edit(embed=self.embed) return - # verify we can actually use the pagination session - if not self.permissions.add_reactions: - raise CannotPaginate('Bot does not have add reactions permission.') - - if not self.permissions.read_message_history: - raise CannotPaginate('Bot does not have Read Message History permission.') - p.append('') p.append('Confused? React with \N{INFORMATION SOURCE} for more info.') self.embed.description = '\n'.join(p) - self.message = await self.bot.send_message(self.message.channel, embed=self.embed) + self.message = await self.channel.send(embed=self.embed) for (reaction, _) in self.reaction_emojis: if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'): # no |<< or >>| buttons if we only have two pages @@ -104,7 +115,7 @@ class Pages: # it from the default set continue - await self.bot.add_reaction(self.message, reaction) + await self.message.add_reaction(reaction) async def checked_show_page(self, page): if page != 0 and page <= self.maximum_pages: @@ -133,40 +144,45 @@ class Pages: async def numbered_page(self): """lets you type a page number to go to""" to_delete = [] - to_delete.append(await self.bot.send_message(self.message.channel, 'What page do you want to go to?')) - msg = await self.bot.wait_for_message(author=self.author, channel=self.message.channel, - check=lambda m: m.content.isdigit(), timeout=30.0) - if msg is not None: + to_delete.append(await self.channel.send('What page do you want to go to?')) + + def message_check(m): + return m.author == self.author and \ + self.channel == m.channel and \ + m.content.isdigit() + + try: + msg = await self.bot.wait_for('message', check=message_check, timeout=30.0) + except asyncio.TimeoutError: + to_delete.append(await self.channel.send('Took too long.')) + await asyncio.sleep(5) + else: page = int(msg.content) to_delete.append(msg) if page != 0 and page <= self.maximum_pages: await self.show_page(page) else: - to_delete.append(await self.bot.say('Invalid page given. (%s/%s)' % (page, self.maximum_pages))) + to_delete.append(await self.channel.send(f'Invalid page given. ({page}/{self.maximum_pages})')) await asyncio.sleep(5) - else: - to_delete.append(await self.bot.send_message(self.message.channel, 'Took too long.')) - await asyncio.sleep(5) try: - await self.bot.delete_messages(to_delete) + await self.channel.delete_messages(to_delete) except Exception: pass async def show_help(self): """shows this message""" - e = discord.Embed() messages = ['Welcome to the interactive paginator!\n'] messages.append('This interactively allows you to see pages of text by navigating with ' \ 'reactions. They are as follows:\n') for (emoji, func) in self.reaction_emojis: - messages.append('%s %s' % (emoji, func.__doc__)) + messages.append(f'{emoji} {func.__doc__}') - e.description = '\n'.join(messages) - e.colour = 0x738bd7 # blurple - e.set_footer(text='We were on page %s before this message.' % self.current_page) - await self.bot.edit_message(self.message, embed=e) + self.embed.description = '\n'.join(messages) + self.embed.clear_fields() + self.embed.set_footer(text=f'We were on page {self.current_page} before this message.') + await self.message.edit(embed=self.embed) async def go_back_to_current_page(): await asyncio.sleep(60.0) @@ -176,13 +192,16 @@ class Pages: async def stop_pages(self): """stops the interactive pagination session""" - await self.bot.delete_message(self.message) + await self.message.delete() self.paginating = False def react_check(self, reaction, user): if user is None or user.id != self.author.id: return False + if reaction.message.id != self.message.id: + return False + for (emoji, func) in self.reaction_emojis: if reaction.emoji == emoji: self.match = func @@ -191,22 +210,300 @@ class Pages: async def paginate(self): """Actually paginate the entries and run the interactive loop if necessary.""" - await self.show_page(1, first=True) + first_page = self.show_page(1, first=True) + if not self.paginating: + await first_page + else: + # allow us to react to reactions right away if we're paginating + self.bot.loop.create_task(first_page) while self.paginating: - react = await self.bot.wait_for_reaction(message=self.message, check=self.react_check, timeout=120.0) - if react is None: + try: + reaction, user = await self.bot.wait_for('reaction_add', check=self.react_check, timeout=120.0) + except asyncio.TimeoutError: self.paginating = False try: - await self.bot.clear_reactions(self.message) + await self.message.clear_reactions() except: pass finally: break try: - await self.bot.remove_reaction(self.message, react.reaction.emoji, react.user) + await self.message.remove_reaction(reaction, user) except: pass # can't remove it so don't bother doing so await self.match() + +class FieldPages(Pages): + """Similar to Pages except entries should be a list of + tuples having (key, value) to show as embed fields instead. + """ + async def show_page(self, page, *, first=False): + self.current_page = page + entries = self.get_page(page) + + self.embed.clear_fields() + self.embed.description = discord.Embed.Empty + + for key, value in entries: + self.embed.add_field(name=key, value=value, inline=False) + + if self.maximum_pages > 1: + if self.show_entry_count: + text = f'Page {page}/{self.maximum_pages} ({len(self.entries)} entries)' + else: + text = f'Page {page}/{self.maximum_pages}' + + self.embed.set_footer(text=text) + + if not self.paginating: + return await self.channel.send(embed=self.embed) + + if not first: + await self.message.edit(embed=self.embed) + return + + self.message = await self.channel.send(embed=self.embed) + for (reaction, _) in self.reaction_emojis: + if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'): + # no |<< or >>| buttons if we only have two pages + # we can't forbid it if someone ends up using it but remove + # it from the default set + continue + + await self.message.add_reaction(reaction) + +import itertools +import inspect +import re + +# ?help +# ?help Cog +# ?help command +# -> could be a subcommand + +_mention = re.compile(r'<@\!?([0-9]{1,19})>') + +def cleanup_prefix(bot, prefix): + m = _mention.match(prefix) + if m: + user = bot.get_user(int(m.group(1))) + if user: + return f'@{user.name} ' + return prefix + +async def _can_run(cmd, ctx): + try: + return await cmd.can_run(ctx) + except: + return False + +def _command_signature(cmd): + # this is modified from discord.py source + # which I wrote myself lmao + + result = [cmd.qualified_name] + if cmd.usage: + result.append(cmd.usage) + return ' '.join(result) + + params = cmd.clean_params + if not params: + return ' '.join(result) + + for name, param in params.items(): + if param.default is not param.empty: + # We don't want None or '' to trigger the [name=value] case and instead it should + # do [name] since [name=None] or [name=] are not exactly useful for the user. + should_print = param.default if isinstance(param.default, str) else param.default is not None + if should_print: + result.append(f'[{name}={param.default!r}]') + else: + result.append(f'[{name}]') + elif param.kind == param.VAR_POSITIONAL: + result.append(f'[{name}...]') + else: + result.append(f'<{name}>') + + return ' '.join(result) + +class HelpPaginator(Pages): + def __init__(self, ctx, entries, *, per_page=4): + super().__init__(ctx, entries=entries, per_page=per_page) + self.reaction_emojis.append(('\N{WHITE QUESTION MARK ORNAMENT}', self.show_bot_help)) + self.total = len(entries) + + @classmethod + async def from_cog(cls, ctx, cog): + cog_name = cog.__class__.__name__ + + # get the commands + entries = sorted(ctx.bot.get_cog_commands(cog_name), key=lambda c: c.name) + + # remove the ones we can't run + entries = [cmd for cmd in entries if (await _can_run(cmd, ctx)) and not cmd.hidden] + + self = cls(ctx, entries) + self.title = f'{cog_name} Commands' + self.description = inspect.getdoc(cog) + self.prefix = cleanup_prefix(ctx.bot, ctx.prefix) + + # no longer need the database + #await ctx.release() + + return self + + @classmethod + async def from_command(cls, ctx, command): + try: + entries = sorted(command.commands, key=lambda c: c.name) + except AttributeError: + entries = [] + else: + entries = [cmd for cmd in entries if (await _can_run(cmd, ctx)) and not cmd.hidden] + + self = cls(ctx, entries) + self.title = command.signature + + if command.description: + self.description = f'{command.description}\n\n{command.help}' + else: + self.description = command.help or 'No help given.' + + self.prefix = cleanup_prefix(ctx.bot, ctx.prefix) + #await ctx.release() + return self + + @classmethod + async def from_bot(cls, ctx): + def key(c): + return c.cog_name or '\u200bMisc' + + entries = sorted(ctx.bot.commands, key=key) + nested_pages = [] + per_page = 9 + + # 0: (cog, desc, commands) (max len == 9) + # 1: (cog, desc, commands) (max len == 9) + # ... + + for cog, commands in itertools.groupby(entries, key=key): + plausible = [cmd for cmd in commands if (await _can_run(cmd, ctx)) and not cmd.hidden] + if len(plausible) == 0: + continue + + description = ctx.bot.get_cog(cog) + if description is None: + description = discord.Embed.Empty + else: + description = inspect.getdoc(description) or discord.Embed.Empty + + nested_pages.extend((cog, description, plausible[i:i + per_page]) for i in range(0, len(plausible), per_page)) + + self = cls(ctx, nested_pages, per_page=1) # this forces the pagination session + self.prefix = cleanup_prefix(ctx.bot, ctx.prefix) + #await ctx.release() + + # swap the get_page implementation with one that supports our style of pagination + self.get_page = self.get_bot_page + self._is_bot = True + + # replace the actual total + self.total = sum(len(o) for _, _, o in nested_pages) + return self + + def get_bot_page(self, page): + cog, description, commands = self.entries[page - 1] + self.title = f'{cog} Commands' + self.description = description + return commands + + async def show_page(self, page, *, first=False): + self.current_page = page + entries = self.get_page(page) + + self.embed.clear_fields() + self.embed.description = self.description + self.embed.title = self.title + + if hasattr(self, '_is_bot'): + value ='For more help, join the official bot support server: https://discord.gg/pYuKF2Z' + self.embed.add_field(name='Support', value=value, inline=False) + + self.embed.set_footer(text=f'Use "{self.prefix}help command" for more info on a command.') + + signature = _command_signature + + for entry in entries: + self.embed.add_field(name=signature(entry), value=entry.short_doc or "No help given", inline=False) + + if self.maximum_pages: + self.embed.set_author(name=f'Page {page}/{self.maximum_pages} ({self.total} commands)') + + if not self.paginating: + return await self.channel.send(embed=self.embed) + + if not first: + await self.message.edit(embed=self.embed) + return + + self.message = await self.channel.send(embed=self.embed) + for (reaction, _) in self.reaction_emojis: + if self.maximum_pages == 2 and reaction in ('\u23ed', '\u23ee'): + # no |<< or >>| buttons if we only have two pages + # we can't forbid it if someone ends up using it but remove + # it from the default set + continue + + await self.message.add_reaction(reaction) + + async def show_help(self): + """shows this message""" + + self.embed.title = 'Paginator help' + self.embed.description = 'Hello! Welcome to the help page.' + + messages = [f'{emoji} {func.__doc__}' for emoji, func in self.reaction_emojis] + self.embed.clear_fields() + self.embed.add_field(name='What are these reactions for?', value='\n'.join(messages), inline=False) + + self.embed.set_footer(text=f'We were on page {self.current_page} before this message.') + await self.message.edit(embed=self.embed) + + async def go_back_to_current_page(): + await asyncio.sleep(30.0) + await self.show_current_page() + + self.bot.loop.create_task(go_back_to_current_page()) + + async def show_bot_help(self): + """shows how to use the bot""" + + self.embed.title = 'Using the bot' + self.embed.description = 'Hello! Welcome to the help page.' + self.embed.clear_fields() + + entries = ( + ('', 'This means the argument is __**required**__.'), + ('[argument]', 'This means the argument is __**optional**__.'), + ('[A|B]', 'This means the it can be __**either A or B**__.'), + ('[argument...]', 'This means you can have multiple arguments.\n' \ + 'Now that you know the basics, it should be noted that...\n' \ + '__**You do not type in the brackets!**__') + ) + + self.embed.add_field(name='How do I use this bot?', value='Reading the bot signature is pretty simple.') + + for name, value in entries: + self.embed.add_field(name=name, value=value, inline=False) + + self.embed.set_footer(text=f'We were on page {self.current_page} before this message.') + await self.message.edit(embed=self.embed) + + async def go_back_to_current_page(): + await asyncio.sleep(30.0) + await self.show_current_page() + + self.bot.loop.create_task(go_back_to_current_page()) \ No newline at end of file diff --git a/params.json b/params.json index 88bb13d..87236f9 100755 --- a/params.json +++ b/params.json @@ -1,6 +1,5 @@ { - "token": "token", - "bots_key": "don't touch", - "client_id": "client id!", - "carbon_key": "don't touch" + "token": "bot token", + "bots_key": "not required", + "client_id": "client id", } diff --git a/readme.md b/readme.md index a9b36f1..88cc6d2 100755 --- a/readme.md +++ b/readme.md @@ -16,11 +16,11 @@ Il vous faut : ### Installation -Une fois les pré-requis installés et les paramètres édités, placez vous dans le repertoire du bot et lancez ``bot.py`` avec python3 (ex: ``python3 bot.py``) +Une fois les pré-requis installés et ``params.json`` édité, placez vous dans le repertoire de tuxbot et lancez ``bot.py`` avec python3 (ex: ``python3 bot.py``) ## Démarrage -Placez vous dans le repertoire du bot et lancez ``bot.py`` avec python3 (ex: ``python3 bot.py``) +Placez vous dans le repertoire de tuxbot et exécutez ``bot.py`` avec python3 (ex: ``python3 bot.py``) ## Fabriqué avec * [PyCharm](https://www.jetbrains.com/pycharm/) - Editeur de texte payant :3 diff --git a/start.sh b/start.sh deleted file mode 100755 index b14fc8f..0000000 --- a/start.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -title="{TuxBot} - Unix Commander" -echo -e '\033]2;'$title'\007' - -python3 bot.py diff --git a/texts/ci-info.md b/texts/ci-info.md index 682c457..fff5609 100755 --- a/texts/ci-info.md +++ b/texts/ci-info.md @@ -1,13 +1,11 @@ La carte d'identité est un petit système dans tuxbot permetant de vous démarquer de vos amis en ayant la possibilité d'y renseigner plusieurs informations ! **Liste des commandes : ** --> ci : Affiche l'aide sur les cartes d'identité --> ci show _pseudo_ : Affiche la carte d'identité de _pseudo_ --> ci register : Vous enregistre dans la base de donnée des cartes d'identité --> ci setos _nom de l'os_ : Défini le système d'exploitation --> ci setconfig _votre configuration pc_ : Défini la configuration de votre ordinateur --> ci setcountry : Défini votre pays -<<<<<<< HEAD --> ci upimage : Met à jour votre image si vous l'avez changé :wink: -======= ->>>>>>> master +-> .ci : Affiche l'aide sur les cartes d'identité +-> .ci show _pseudo_ : Affiche la carte d'identité de _pseudo_ +-> .ci register : Vous enregistre dans la base de donnée des cartes d'identité +-> .ci setos _nom de l'os_ : Défini votre système d'exploitation +-> .ci setconfig _votre configuration pc_ : Défini la configuration de votre ordinateur +-> .ci setcountry : Défini votre pays +-> .ci update : Met à jour votre image si vous l'avez changé :wink: +-> .ci delete : Supprime votre carte d'identité :sob: diff --git a/texts/help.md b/texts/help.md index e3c314a..cdd1bb9 100755 --- a/texts/help.md +++ b/texts/help.md @@ -1,45 +1,35 @@ **Commandes utilitaires** --> afk : Signaler son absence --> back : Signaler son retour --> clock _ville_: Affiche l'heure et quelques infos sur la ville en question --> search _site_ _contenu_ : Fait une recherche sur un site (.search pour plus d'infos) --> avatar _@pseudo_ : Récupère l'avatar de _@pseudo_ -<<<<<<< HEAD --> poke _@pseudo_ : Poke _@pseudo_ -======= --> btcprice : Affiche le prix du bitcoin en euro ->>>>>>> master +-> .afk : Signaler son absence +-> .back : Signaler son retour +-> .clock _ville_: Affiche l'heure et quelques infos sur la ville en question +-> .ytdiscover : Découvrir des chaines youtube +-> .search _site_ _contenu_ : Fait une recherche sur un site (.search pour plus d'infos) +-> .avatar _@pseudo_ : Récupère l'avatar de _@pseudo_ +-> .poke _@pseudo_ : Poke _@pseudo_ +-> .hastebin _code_ : Poste du code sur hastebin +-> .sondage _question_ | _reponse_ | _reponse_ | _option_ : Créer un sondage avec des réactions +-> .sondage_aide : Affiche l'aide pour la commande sondage **Commandes Funs** --> joke : Affiche une blague aléatoire --> ethylotest : Simule un ethylotest détraqué --> pokemon : Lance un combat de pokémons aléatoires --> coin : Simule un pile ou face --> randomcat : Affiche des image de chats :3 --> ytdiscover : Découvrir des chaines youtube +-> .joke : Affiche une blague aléatoire +-> .ethylotest : Simule un ethylotest détraqué +-> .pokemon : Lance un combat de pokémons +-> .coin : Simule un pile ou face +-> .randomcat : Affiche des image de chats :3 **Commandes Carte d'Identité** --> ci : Affiche l'aide sur les cartes d'identité --> ci show _pseudo_ : Affiche la carte d'identité de _pseudo_ --> ci register : Vous enregistre dans la base de donnée des cartes d'identité --> ci setos _nom de l'os_ : Défini le système d'exploitation --> ci setconfig _votre configuration pc_ : Défini la configuration de votre ordinateur -<<<<<<< HEAD --> ci setcountry : Défini votre pays --> ci upimage : Met à jour votre image si vous l'avez changé :wink: - -**Commandes d'administration** -======= --> ci setcountry : Défini votre pays - -** Commandes d'administration ** ->>>>>>> master --> say _votre message_ : Envoi un message de la part du bot --> clear _nombre_ : Supprime _nombre_ de messages +-> .ci : Affiche l'aide sur les cartes d'identité +-> .ci show _pseudo_ : Affiche la carte d'identité de _pseudo_ +-> .ci register : Vous enregistre dans la base de donnée des cartes d'identité +-> .ci setos _nom de l'os_ : Défini le système d'exploitation +-> .ci setconfig _votre configuration pc_ : Défini la configuration de votre ordinateur +-> .ci setcountry : Défini votre pays +-> .ci update : Met à jour votre image si vous l'avez changé :wink: +-> .ci delete : Supprime votre carte d'identité **a tous jamais** **Commandes diverses** : --> info : Affiche des informations sur le bot --> help : Affiche ce message --> clock list: Affiche la liste des horloges des villes --> ping : Ping le bot --> github : Affiche le repos Github du Bot :heart: +-> .info : Affiche des informations sur le bot +-> .help : Affiche ce message +-> .clock list: Affiche la liste des horloges des villes +-> .ping : Ping le bot +-> .github : Affiche le repos Github du Bot :heart: diff --git a/texts/info.md b/texts/info.md index 8fc161a..9dbdf15 100755 --- a/texts/info.md +++ b/texts/info.md @@ -1,18 +1,23 @@ -==> **Développement** : -└> Outout : [outout.tech](https://outout.tech/) -└> Romain : [son github](https://github.com/Rom194) -└> Langage : [Python3](http://www.python.org/) -└> Api : [discord.py {3}](https://github.com/Rapptz/discord.py) -└> En se basant sur : [RobotDanny](https://github.com/Rapptz/RoboDanny) +<:stafftools:314348604095594498> **Développement** : + └> Outout : [outout.tech](https://outout.tech/) + └> Romain : [son github](https://github.com/Rom194) + └> Langage : [Python3](http://www.python.org/) + └> Api : [discord.py {3}](https://github.com/Rapptz/discord.py) + └> En se basant sur : [RobotDanny](https://github.com/Rapptz/RoboDanny) -==> **Hébergé sur "{2}"**: -└> OS : {0} -└> Version de Python : {1} +<:server:334347432835940352> **Hébergé sur "{2}"**: + └> <:tux:282212977627758593> OS : {0} + └> <:python:334346615366221825> Version : {1} + +<:contact:334347787200233483> **Contact** : + └> <:discord:314003252830011395> : Outout#8406 + └> <:twitter:314349922877046786> : [@outout14_](https://twitter.com/outout14_) + └> <:mail:334345653419245571> : [outout@linuxmail.org](mailto:outout@linuxmail.org) + + +<:discord:314003252830011395> **Serveurs** : + └> <:tux:282212977627758593> Serveur de TuxBot : [rejoindre](https://discord.gg/5UZy8Pn) + └> <:tux:282212977627758593> Serveur GNU/Linux-Fr : [rejoindre](https://discord.gg/B5TzW7x) -==> **Contact** : -└> Discord : Outout#8406 -└> Mail : [outout@linuxmail.org](mailto:outout@linuxmail.org) -==> **Serveur Discord d'Origine** : -└> Aide GNU/Linux-Fr : [rejoindre](https://discord.gg/B5TzW7x) diff --git a/texts/jokes.json b/texts/jokes.json index e7d066b..305de47 100755 --- a/texts/jokes.json +++ b/texts/jokes.json @@ -10,5 +10,6 @@ "9": {"content": "Les appareils apple ont ils une adresse personnalisée ?", "author": "Outout"}, "10": {"content": "Le 1er janvier 1970 c'est le jour où il y a eu le plus de plantages. (cf : http://bit.ly/2rArLVe)", "author": "NyoSan"}, "11": {"content": "Pourquoi est-ce que les girafes aiment magasiner à bas prix? Tout est une question de cou.", "author": "Maxx_Qc (bukkit.fr)"}, - "12": {"content": "``Même éteint le hackeur peut pirater l'ordi`` \"Le SuperGeek tournant sous Ubuntu (ou Windows)\"", "author": "Outout"} -} + "12": {"content": "``Même éteint le hackeur peut pirater l'ordi`` \"Le SuperGeek tournant sous Ubuntu (ou Windows)\"", "author": "Outout"}, + "13": {"content": "Trois ingénieurs (1 chimiste, 1 électronicien, 1 Microsoft) dans un bus roulant dans un désert. \n\n Le bus « tombe en panne » sans raison apparente, et voila les 3 gars à discuter. \n L’électronicien : je pourrais regarder les circuits et voir si quelque chose cloche. \n Le chimiste : on devrait vérifier l'essence avant. \n L’ingé Microsoft : non, on remonte dans le bus, on ferme toutes les fenêtres, et logiquement ça devrait redémarrer.", "author": "Internet"} +} \ No newline at end of file diff --git a/texts/rpoll.md b/texts/rpoll.md new file mode 100644 index 0000000..b8fd83f --- /dev/null +++ b/texts/rpoll.md @@ -0,0 +1,14 @@ +**Créez un sondage avec les réactions !** + +**Usage** : +``.sondage | | | `` Vous pouvez utiliser autant de réponses que vous le souhaitez, en plaçant un symbole | entre chaque choix. + +**Exemple**: +``.sondage Quelle est votre couleur préférée ? | Rouge | Vert | Bleu | Autre`` + + +**Definir un temps limite** : +Vous pouvez également utiliser l'option "time" pour définir le temps en secondes pendant lequel le sondage durera. + +**Exemple**: +``.sondage Utilisez vous twitteur ? | Oui | Non | Pas souvent | time=10``. diff --git a/texts/search.md b/texts/search.md index f17a132..42078b6 100755 --- a/texts/search.md +++ b/texts/search.md @@ -3,4 +3,4 @@ _Attention ! entrez vos termes de recherche sans espaces !_ Pour effectuer une recherche utilisez la commande ``.search {site_de_recherche} {termes_recherche}`` -> [**docubuntu**](https://doc.ubuntu-fr.org) : Effectuer une recherche sur un paquet dans la Documentation du site ubuntu-fr.org. -> [**wikipedia**](https://fr.wikipedia.org) : Effectuer une recherche sur l'encyclopédie libre Wikipedia en Français ! --> [**aur.archlinux**](https://aur.archlinux.org) : Effectuer une recherche sur Archlinux Aur ! +-> [**aur**](https://aur.archlinux.org) : Effectuer une recherche sur Archlinux Aur !