Et bim V6
ET y'a les cogs mon p'tit tabarnak !
This commit is contained in:
parent
1ee3811ef2
commit
4fd8826d22
47 changed files with 2473 additions and 762 deletions
70
cogs/admin.py
Normal file
70
cogs/admin.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
from discord.ext import commands
|
||||
from random import choice, shuffle
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import time
|
||||
import discord
|
||||
import platform
|
||||
from .utils import checks
|
||||
|
||||
class Admin:
|
||||
"""Commandes secrètes d'administration."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@checks.is_owner()
|
||||
@commands.command()
|
||||
async def unload(self, module: str):
|
||||
"""Unloads a module."""
|
||||
try:
|
||||
self.bot.unload_extension(module)
|
||||
except Exception as e:
|
||||
await self.bot.say('\N{PISTOL}')
|
||||
await self.bot.say('{}: {}'.format(type(e).__name__, e))
|
||||
else:
|
||||
await self.bot.say('\N{OK HAND SIGN}')
|
||||
|
||||
@checks.is_owner()
|
||||
@commands.command(name='reload_cog', hidden=True)
|
||||
async def _reload(self, *, module: str):
|
||||
"""Reloads a module."""
|
||||
try:
|
||||
self.bot.unload_extension(module)
|
||||
self.bot.load_extension(module)
|
||||
await self.bot.say("Nice !")
|
||||
except Exception as e:
|
||||
await self.bot.say(':( Erreur :')
|
||||
await self.bot.say('{}: {}'.format(type(e).__name__, e))
|
||||
else:
|
||||
await self.bot.say('\N{OK HAND SIGN}')
|
||||
|
||||
@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:
|
||||
await self.bot.say(':sob: Une erreur est survenue : \n {}: {}'.format(type(e).__name__, e))
|
||||
|
||||
@checks.is_owner()
|
||||
@commands.command(name='say', pass_context=True, hidden=True)
|
||||
async def _say(self, ctx, dire):
|
||||
try:
|
||||
arg = ctx.message.content.split("say ")
|
||||
await self.bot.say(arg[1])
|
||||
await self.bot.delete_message(ctx.message)
|
||||
except Exception as e:
|
||||
await self.bot.say(':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):
|
||||
clear = "\n" * 100
|
||||
print(clear)
|
||||
await self.bot.say(":ok_hand: It's good")
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Admin(bot))
|
42
cogs/basics.py
Normal file
42
cogs/basics.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
from discord.ext import commands
|
||||
from random import choice, shuffle
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import time
|
||||
import discord
|
||||
import platform, socket
|
||||
import os
|
||||
|
||||
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 !")
|
||||
|
||||
##INFO##
|
||||
@commands.command()
|
||||
async def info(self):
|
||||
"""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)
|
||||
|
||||
|
||||
## HELP PLZ ##
|
||||
@commands.command()
|
||||
async def help(self):
|
||||
"""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)
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(General(bot))
|
144
cogs/ci.py
Normal file
144
cogs/ci.py
Normal file
|
@ -0,0 +1,144 @@
|
|||
from discord.ext import commands
|
||||
from random import choice, shuffle
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import discord
|
||||
import platform, socket
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
#### SQL #####
|
||||
conn = sqlite3.connect('tuxbot.db') #Connexion SQL
|
||||
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS users(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
userid TEXT,
|
||||
username TEXT,
|
||||
os TEXT,
|
||||
config TEXT,
|
||||
useravatar TEXT,
|
||||
userbirth TEXT,
|
||||
pays TEXT,
|
||||
cidate TEXT,
|
||||
cibureau TEXT
|
||||
)
|
||||
""")# Creation table Utilisateur si premiere fois
|
||||
conn.commit()
|
||||
|
||||
class Identity:
|
||||
"""Commandes des cartes d'identité ."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.group(name="ci", no_pm=True, pass_context=True)
|
||||
async def _ci(self, ctx):
|
||||
"""Cartes d'identité"""
|
||||
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)
|
||||
|
||||
@_ci.command(pass_context=True, name="show")
|
||||
async def ci_test(self, ctx, args : discord.Member):
|
||||
|
||||
def isexist(var):
|
||||
if not var:
|
||||
return "Non renseigné."
|
||||
else:
|
||||
return var
|
||||
|
||||
cursor.execute("""SELECT userid, username, useravatar, userbirth, cidate, cibureau, os, config, pays 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))
|
||||
|
||||
else:
|
||||
userbirth = result[3].split(" ")
|
||||
cidate = result[4].split(" ")
|
||||
embed=discord.Embed(title="Carte d'identité | Communisme Linuxien")
|
||||
embed.set_author(name=result[1], icon_url=result[2])
|
||||
embed.set_thumbnail(url = result[2])
|
||||
embed.add_field(name="Nom :", value=result[1], inline=True)
|
||||
embed.add_field(name="Système d'exploitation :", value=isexist(result[6]), inline=True)
|
||||
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.set_footer(text="Enregistré dans le bureau {} le {}.".format(result[5], cidate[0]))
|
||||
await self.bot.say(embed=embed)
|
||||
|
||||
@_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")
|
||||
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))
|
||||
|
||||
@_ci.command(pass_context=True, name="setconfig")
|
||||
async def ci_setconfig(self, ctx, args_):
|
||||
try:
|
||||
args = ctx.message.content.split("setconfig ")
|
||||
args = args[1]
|
||||
cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,))
|
||||
existansw = cursor.fetchone()
|
||||
|
||||
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 !")
|
||||
else:
|
||||
await self.bot.say(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 !")
|
||||
|
||||
@_ci.command(pass_context=True, name="setos")
|
||||
async def ci_setos(self, ctx, args_):
|
||||
try:
|
||||
args = ctx.message.content.split("setos ")
|
||||
args = args[1]
|
||||
cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,))
|
||||
existansw = cursor.fetchone()
|
||||
|
||||
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 !")
|
||||
else:
|
||||
await self.bot.say(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 !")
|
||||
|
||||
@_ci.command(pass_context=True, name="setcountry")
|
||||
async def ci_setcountry(self, ctx, args):
|
||||
cursor.execute("""SELECT id, userid FROM users WHERE userid=?""", (ctx.message.author.id,))
|
||||
existansw = cursor.fetchone()
|
||||
|
||||
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 !")
|
||||
else:
|
||||
await self.bot.say(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):
|
||||
cursor.execute("""SELECT id, username FROM users""")
|
||||
rows = cursor.fetchall()
|
||||
msg = ""
|
||||
try:
|
||||
for row in rows:
|
||||
msg = msg + '{0} : {1} \n'.format(row[0], row[1])
|
||||
await self.bot.say(msg)
|
||||
except:
|
||||
await self.bot.say(":x: Pas d'entrés")
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Identity(bot))
|
124
cogs/funs.py
Normal file
124
cogs/funs.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
from discord.ext import commands
|
||||
from random import choice, shuffle
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import discord
|
||||
import urllib.request, json
|
||||
import random
|
||||
import requests
|
||||
|
||||
class Funs:
|
||||
"""Commandes funs."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
|
||||
|
||||
@commands.command()
|
||||
async def avatar(self, 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)
|
||||
|
||||
@commands.command()
|
||||
async def btcprice(self):
|
||||
"""Le prix du BTC"""
|
||||
loading = await self.bot.say("_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())
|
||||
btc = data['bpi']['EUR']['rate']
|
||||
btc = btc.split(".")
|
||||
except:
|
||||
btc = 1
|
||||
|
||||
if btc == 1:
|
||||
await self.bot.say("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] + " €")
|
||||
|
||||
@commands.command()
|
||||
async def joke(self):
|
||||
"""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))
|
||||
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)
|
||||
|
||||
@commands.command()
|
||||
async def ethylotest(self):
|
||||
"""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 prolbè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..._"]
|
||||
|
||||
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 asyncio.sleep(0.5)
|
||||
await self.bot.say(":man: " + result_c)
|
||||
await asyncio.sleep(1)
|
||||
await self.bot.say(":police_car: " + result_p)
|
||||
|
||||
@commands.command()
|
||||
async def coin(self):
|
||||
"""Coin flip simulator 2025"""
|
||||
starts_msg = ["Je lance la pièce !", "C'est partit !", "C'est une pièce de d'un cent faut pas la perdre", "C'est une pièce de 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} How shit, je crois que je l'ai perdu", "{1} Et bim je te vol ta pièce !", "{0} Oh une erreur d'impression y'a ni pile ni face !"]
|
||||
|
||||
start = random.choice(starts_msg)
|
||||
result = random.choice(results_coin)
|
||||
|
||||
await self.bot.say(start)
|
||||
await asyncio.sleep(0.6)
|
||||
await self.bot.say(result.format(":moneybag: Et la pièce retombe sur ...", ":robot:"))
|
||||
|
||||
@commands.command()
|
||||
async def pokemon(self):
|
||||
"""Random pokemon fight"""
|
||||
with open('texts/pokemons.json') as js:
|
||||
jk = json.load(js)
|
||||
|
||||
poke1 = jk[random.randint(1, 150)]
|
||||
poke2 = jk[random.randint(1, 150)]
|
||||
|
||||
if poke1['MaxHP'] > poke2['MaxHP']:
|
||||
winer = poke1
|
||||
else:
|
||||
winer = poke2
|
||||
|
||||
await self.bot.say(":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 asyncio.sleep(0.5)
|
||||
await self.bot.say(":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 asyncio.sleep(1.2)
|
||||
await self.bot.say("_le combat continue de se dérouler..._")
|
||||
await asyncio.sleep(1.5)
|
||||
await self.bot.say(":trophy: Le gagnant est **{}** !".format(winer["Name"]))
|
||||
|
||||
@commands.command()
|
||||
async def randomcat(self):
|
||||
"""Display a random cat"""
|
||||
|
||||
r = requests.get('http://random.cat/meow.php')
|
||||
cat = str(r.json()['file'])
|
||||
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)
|
||||
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Funs(bot))
|
122
cogs/search.py
Normal file
122
cogs/search.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
from discord.ext import commands
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import discord
|
||||
import urllib.request, json
|
||||
import wikipedia, bs4
|
||||
|
||||
wikipedia.set_lang("fr")
|
||||
|
||||
class Search:
|
||||
"""Commandes de WWW."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.group(name="search", no_pm=True, pass_context=True)
|
||||
async def _search(self, ctx):
|
||||
"""Rechercher sur le world wide web"""
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
||||
@_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))
|
||||
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)
|
||||
else:
|
||||
await self.bot.delete_message(attends)
|
||||
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)
|
||||
|
||||
@_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))
|
||||
erreur = 0
|
||||
try:
|
||||
html = urllib.request.urlopen("https://aur.archlinux.org/packages/" + args).read()
|
||||
except:
|
||||
erreur = 1
|
||||
|
||||
if erreur == 1:
|
||||
await self.bot.delete_message(attends)
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@_search.command(pass_context=True, name="wikipedia")
|
||||
async def search_wikipedia(self, ctx, args):
|
||||
"""Fait une recherche sur wikipd"""
|
||||
try:
|
||||
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)
|
||||
|
||||
em = discord.Embed(title='Résultats de : ' + args, description = msg, colour=0x4ECDC4)
|
||||
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)
|
||||
|
||||
list_emojis = ["1⃣", "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟"]
|
||||
|
||||
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:
|
||||
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:
|
||||
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))
|
126
cogs/utility.py
Normal file
126
cogs/utility.py
Normal file
|
@ -0,0 +1,126 @@
|
|||
from discord.ext import commands
|
||||
from random import choice, shuffle
|
||||
import random
|
||||
import aiohttp
|
||||
import asyncio
|
||||
import time
|
||||
import discord
|
||||
import urllib.request, json
|
||||
import datetime, pytz
|
||||
|
||||
class Utility:
|
||||
"""Commandes utilitaires."""
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
|
||||
@commands.command()
|
||||
async def clock(self, args):
|
||||
"""Display hour in a country"""
|
||||
args = args.upper()
|
||||
then = datetime.datetime.now(pytz.utc)
|
||||
form = '%H heures %M'
|
||||
try:
|
||||
argument = args[1]
|
||||
if args == "MONTREAL":
|
||||
utc = then.astimezone(pytz.timezone('America/Montreal'))
|
||||
site = "http://ville.montreal.qc.ca/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/e/e0/Rentier_fws_1.jpg"
|
||||
country = "au Canada, Québec"
|
||||
description = "Montréal est la deuxième ville la plus peuplée du Canada. Elle se situe dans la région du Québec"
|
||||
elif args == "VANCOUVER":
|
||||
utc = then.astimezone(pytz.timezone('America/Vancouver'))
|
||||
site = "http://vancouver.ca/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/f/fe/Dock_Vancouver.JPG"
|
||||
country = "au Canada"
|
||||
description = "Vancouver, officiellement City of Vancouver, est une cité portuaire au Canada"
|
||||
elif args == "NEW-YORK" or args == "N-Y":
|
||||
utc = then.astimezone(pytz.timezone('America/New_York'))
|
||||
site = "http://www1.nyc.gov/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/e/e3/NewYork_LibertyStatue.jpg"
|
||||
country = "aux U.S.A."
|
||||
description = "New York, est la plus grande ville des États-Unis en termes d'habitants et l'une des plus importantes du continent américain. "
|
||||
elif args == "LOSANGELES" or args == "L-A" or args == "LA" or args == "LACITY":
|
||||
utc = then.astimezone(pytz.timezone('America/Los_Angeles'))
|
||||
site = "https://www.lacity.org/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/thumb/5/57/LA_Skyline_Mountains2.jpg/800px-LA_Skyline_Mountains2.jpg"
|
||||
country = "aux U.S.A."
|
||||
description = "Los Angeles est la deuxième ville la plus peuplée des États-Unis après New York. Elle est située dans le sud de l'État de Californie, sur la côte pacifique."
|
||||
elif args == "PARIS":
|
||||
utc = then.astimezone(pytz.timezone('Europe/Paris'))
|
||||
site = "http://www.paris.fr/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/a/af/Tour_eiffel_at_sunrise_from_the_trocadero.jpg"
|
||||
country = "en France"
|
||||
description = "Paris est la capitale de la France. Elle se situe au cœur d'un vaste bassin sédimentaire aux sols fertiles et au climat tempéré, le bassin parisien."
|
||||
elif args == "BERLIN":
|
||||
utc = then.astimezone(pytz.timezone('Europe/Berlin'))
|
||||
site = "http://www.berlin.de/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/9/91/Eduard_Gaertner_Schlossfreiheit.jpg"
|
||||
country = "en Allemagne"
|
||||
description = "Berlin est la capitale et la plus grande ville d'Allemagne. Située dans le nord-est du pays, elle compte environ 3,5 millions d'habitants. "
|
||||
elif args == "BERN" or args == "ZURICH" or args == "BERNE":
|
||||
utc = then.astimezone(pytz.timezone('Europe/Zurich'))
|
||||
site = "http://www.berne.ch/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/d/db/Justitia_Statue_02.jpg"
|
||||
country = "en Suisse"
|
||||
description = "Berne est la cinquième plus grande ville de Suisse et la capitale du canton homonyme. Depuis 1848, Berne est la « ville fédérale »."
|
||||
elif args == "TOKYO":
|
||||
utc = then.astimezone(pytz.timezone('Asia/Tokyo'))
|
||||
site = "http://www.gotokyo.org/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/3/37/TaroTokyo20110213-TokyoTower-01.jpg"
|
||||
country = "au Japon"
|
||||
description = "Tokyo, anciennement Edo, officiellement la préfecture métropolitaine de Tokyo, est la capitale du Japon."
|
||||
elif args == "MOSCOU":
|
||||
utc = then.astimezone(pytz.timezone('Europe/Moscow'))
|
||||
site = "https://www.mos.ru/"
|
||||
img = "https://upload.wikimedia.org/wikipedia/commons/f/f7/Andreyevsky_Zal.jpg"
|
||||
country = "en Russie"
|
||||
description = "Moscou est la capitale de la Fédération de Russie et la plus grande ville d'Europe. Moscou est situé sur la rivière Moskova. "
|
||||
try:
|
||||
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)
|
||||
else:
|
||||
tt = utc.strftime(form)
|
||||
em = discord.Embed(title='Heure à ' + args[1].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)
|
||||
except UnboundLocalError:
|
||||
await self.bot.say("[**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")
|
||||
|
||||
@commands.command()
|
||||
async def ytdiscover(self):
|
||||
"""Random youtube channel"""
|
||||
with open('texts/ytb.json') as js:
|
||||
ytb = json.load(js)
|
||||
|
||||
clef = str(random.randint(0,12))
|
||||
chaine = ytb["{}".format(clef)]
|
||||
|
||||
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)
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
async def afk(self, ctx):
|
||||
"""Away from keyboard"""
|
||||
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))
|
||||
|
||||
@commands.command(pass_context=True)
|
||||
async def back(self, ctx):
|
||||
"""I'm back !"""
|
||||
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))
|
||||
|
||||
|
||||
def setup(bot):
|
||||
bot.add_cog(Utility(bot))
|
0
cogs/utils/__init__.py
Normal file
0
cogs/utils/__init__.py
Normal file
BIN
cogs/utils/__pycache__/__init__.cpython-35.pyc
Normal file
BIN
cogs/utils/__pycache__/__init__.cpython-35.pyc
Normal file
Binary file not shown.
BIN
cogs/utils/__pycache__/checks.cpython-35.pyc
Normal file
BIN
cogs/utils/__pycache__/checks.cpython-35.pyc
Normal file
Binary file not shown.
58
cogs/utils/checks.py
Normal file
58
cogs/utils/checks.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
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(warn=True):
|
||||
def check(ctx, warn):
|
||||
owner = is_owner_check(ctx.message)
|
||||
if not owner and warn:
|
||||
print(ctx.message.author.name + " à essayer d'executer " + ctx.message.content)
|
||||
return owner
|
||||
|
||||
owner = commands.check(lambda ctx: check(ctx, warn))
|
||||
return owner
|
||||
|
||||
def check_permissions(ctx, perms):
|
||||
msg = ctx.message
|
||||
if is_owner_check(msg):
|
||||
return True
|
||||
|
||||
ch = msg.channel
|
||||
author = msg.author
|
||||
resolved = ch.permissions_for(author)
|
||||
return all(getattr(resolved, name, None) == value for name, value in perms.items())
|
||||
|
||||
|
||||
def role_or_permissions(ctx, check, **perms):
|
||||
if check_permissions(ctx, perms):
|
||||
return True
|
||||
|
||||
ch = ctx.message.channel
|
||||
author = ctx.message.author
|
||||
if ch.is_private:
|
||||
return False # can't have roles in PMs
|
||||
|
||||
role = discord.utils.find(check, author.roles)
|
||||
return role is not None
|
||||
|
||||
|
||||
def admin_or_permissions(**perms):
|
||||
def predicate(ctx):
|
||||
return role_or_permissions(ctx, lambda r: r.name == 'Bot Admin', **perms)
|
||||
|
||||
return commands.check(predicate)
|
||||
|
||||
|
||||
def is_in_servers(*server_ids):
|
||||
def predicate(ctx):
|
||||
server = ctx.message.server
|
||||
if server is None:
|
||||
return False
|
||||
return server.id in server_ids
|
||||
|
||||
return commands.check(predicate)
|
67
cogs/utils/config.py
Normal file
67
cogs/utils/config.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
import json
|
||||
import os
|
||||
import uuid
|
||||
import asyncio
|
||||
|
||||
class Config:
|
||||
"""The "database" object. Internally based on ``json``."""
|
||||
|
||||
def __init__(self, name, **options):
|
||||
self.name = name
|
||||
self.object_hook = options.pop('object_hook', None)
|
||||
self.encoder = options.pop('encoder', None)
|
||||
self.loop = options.pop('loop', asyncio.get_event_loop())
|
||||
self.lock = asyncio.Lock()
|
||||
if options.pop('load_later', False):
|
||||
self.loop.create_task(self.load())
|
||||
else:
|
||||
self.load_from_file()
|
||||
|
||||
def load_from_file(self):
|
||||
try:
|
||||
with open(self.name, 'r') as f:
|
||||
self._db = json.load(f, object_hook=self.object_hook)
|
||||
except FileNotFoundError:
|
||||
self._db = {}
|
||||
|
||||
async def load(self):
|
||||
with await self.lock:
|
||||
await self.loop.run_in_executor(None, self.load_from_file)
|
||||
|
||||
def _dump(self):
|
||||
temp = '%s-%s.tmp' % (uuid.uuid4(), self.name)
|
||||
with open(temp, 'w', encoding='utf-8') as tmp:
|
||||
json.dump(self._db.copy(), tmp, ensure_ascii=True, cls=self.encoder, separators=(',', ':'))
|
||||
|
||||
# atomically move the file
|
||||
os.replace(temp, self.name)
|
||||
|
||||
async def save(self):
|
||||
with await self.lock:
|
||||
await self.loop.run_in_executor(None, self._dump)
|
||||
|
||||
def get(self, key, *args):
|
||||
"""Retrieves a config entry."""
|
||||
return self._db.get(key, *args)
|
||||
|
||||
async def put(self, key, value, *args):
|
||||
"""Edits a config entry."""
|
||||
self._db[key] = value
|
||||
await self.save()
|
||||
|
||||
async def remove(self, key):
|
||||
"""Removes a config entry."""
|
||||
del self._db[key]
|
||||
await self.save()
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._db
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self._db[item]
|
||||
|
||||
def __len__(self):
|
||||
return len(self._db)
|
||||
|
||||
def all(self):
|
||||
return self._db
|
75
cogs/utils/formats.py
Normal file
75
cogs/utils/formats.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
async def entry_to_code(bot, entries):
|
||||
width = max(map(lambda t: len(t[0]), entries))
|
||||
output = ['```']
|
||||
fmt = '{0:<{width}}: {1}'
|
||||
for name, entry in entries:
|
||||
output.append(fmt.format(name, entry, width=width))
|
||||
output.append('```')
|
||||
await bot.say('\n'.join(output))
|
||||
|
||||
import datetime
|
||||
|
||||
async def indented_entry_to_code(bot, entries):
|
||||
width = max(map(lambda t: len(t[0]), entries))
|
||||
output = ['```']
|
||||
fmt = '\u200b{0:>{width}}: {1}'
|
||||
for name, entry in entries:
|
||||
output.append(fmt.format(name, entry, width=width))
|
||||
output.append('```')
|
||||
await bot.say('\n'.join(output))
|
||||
|
||||
async def too_many_matches(bot, msg, matches, entry):
|
||||
check = lambda m: m.content.isdigit()
|
||||
await bot.say('There are too many matches... Which one did you mean? **Only say the number**.')
|
||||
await bot.say('\n'.join(map(entry, enumerate(matches, 1))))
|
||||
|
||||
# only give them 3 tries.
|
||||
for i in range(3):
|
||||
message = await bot.wait_for_message(author=msg.author, channel=msg.channel, check=check)
|
||||
index = int(message.content)
|
||||
try:
|
||||
return matches[index - 1]
|
||||
except:
|
||||
await bot.say('Please give me a valid number. {} tries remaining...'.format(2 - i))
|
||||
|
||||
raise ValueError('Too many tries. Goodbye.')
|
||||
|
||||
class Plural:
|
||||
def __init__(self, **attr):
|
||||
iterator = attr.items()
|
||||
self.name, self.value = next(iter(iterator))
|
||||
|
||||
def __str__(self):
|
||||
v = self.value
|
||||
if v > 1:
|
||||
return '%s %ss' % (v, self.name)
|
||||
return '%s %s' % (v, self.name)
|
||||
|
||||
def human_timedelta(dt):
|
||||
now = datetime.datetime.utcnow()
|
||||
delta = now - dt
|
||||
hours, remainder = divmod(int(delta.total_seconds()), 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
days, hours = divmod(hours, 24)
|
||||
years, days = divmod(days, 365)
|
||||
|
||||
if years:
|
||||
if days:
|
||||
return '%s and %s ago' % (Plural(year=years), Plural(day=days))
|
||||
return '%s ago' % Plural(year=years)
|
||||
|
||||
if days:
|
||||
if hours:
|
||||
return '%s and %s ago' % (Plural(day=days), Plural(hour=hours))
|
||||
return '%s ago' % Plural(day=days)
|
||||
|
||||
if hours:
|
||||
if minutes:
|
||||
return '%s and %s ago' % (Plural(hour=hours), Plural(minute=minutes))
|
||||
return '%s ago' % Plural(hour=hours)
|
||||
|
||||
if minutes:
|
||||
if seconds:
|
||||
return '%s and %s ago' % (Plural(minute=minutes), Plural(second=seconds))
|
||||
return '%s ago' % Plural(minute=minutes)
|
||||
return '%s ago' % Plural(second=seconds)
|
147
cogs/utils/maps.py
Normal file
147
cogs/utils/maps.py
Normal file
|
@ -0,0 +1,147 @@
|
|||
#!/bin/env python
|
||||
|
||||
# With credit to DanielKO
|
||||
|
||||
from lxml import etree
|
||||
import datetime, re
|
||||
import asyncio, aiohttp
|
||||
|
||||
NINTENDO_LOGIN_PAGE = "https://id.nintendo.net/oauth/authorize"
|
||||
SPLATNET_CALLBACK_URL = "https://splatoon.nintendo.net/users/auth/nintendo/callback"
|
||||
SPLATNET_CLIENT_ID = "12af3d0a3a1f441eb900411bb50a835a"
|
||||
SPLATNET_SCHEDULE_URL = "https://splatoon.nintendo.net/schedule"
|
||||
|
||||
class Rotation(object):
|
||||
def __init__(self):
|
||||
self.start = None
|
||||
self.end = None
|
||||
self.turf_maps = []
|
||||
self.ranked_mode = None
|
||||
self.ranked_maps = []
|
||||
|
||||
|
||||
@property
|
||||
def is_over(self):
|
||||
return self.end < datetime.datetime.utcnow()
|
||||
|
||||
def __str__(self):
|
||||
now = datetime.datetime.utcnow()
|
||||
prefix = ''
|
||||
if self.start > now:
|
||||
minutes_delta = int((self.start - now) / datetime.timedelta(minutes=1))
|
||||
hours = int(minutes_delta / 60)
|
||||
minutes = minutes_delta % 60
|
||||
prefix = '**In {0} hours and {1} minutes**:\n'.format(hours, minutes)
|
||||
else:
|
||||
prefix = '**Current Rotation**:\n'
|
||||
|
||||
fmt = 'Turf War is {0[0]} and {0[1]}\n{1} is {2[0]} and {2[1]}'
|
||||
return prefix + fmt.format(self.turf_maps, self.ranked_mode, self.ranked_maps)
|
||||
|
||||
# based on https://github.com/Wiwiweb/SakuraiBot/blob/master/src/sakuraibot.py
|
||||
async def get_new_splatnet_cookie(username, password):
|
||||
parameters = {'client_id': SPLATNET_CLIENT_ID,
|
||||
'response_type': 'code',
|
||||
'redirect_uri': SPLATNET_CALLBACK_URL,
|
||||
'username': username,
|
||||
'password': password}
|
||||
|
||||
async with aiohttp.post(NINTENDO_LOGIN_PAGE, data=parameters) as response:
|
||||
cookie = response.history[-1].cookies.get('_wag_session')
|
||||
if cookie is None:
|
||||
print(req)
|
||||
raise Exception("Couldn't retrieve cookie")
|
||||
return cookie
|
||||
|
||||
def parse_splatnet_time(timestr):
|
||||
# time is given as "MM/DD at H:MM [p|a].m. (PDT|PST)"
|
||||
# there is a case where it goes over the year, e.g. 12/31 at ... and then 1/1 at ...
|
||||
# this case is kind of weird though and is currently unexpected
|
||||
# it could even end up being e.g. 12/31/2015 ... and then 1/1/2016 ...
|
||||
# we'll never know
|
||||
|
||||
regex = r'(?P<month>\d+)\/(?P<day>\d+)\s*at\s*(?P<hour>\d+)\:(?P<minutes>\d+)\s*(?P<p>a\.m\.|p\.m\.)\s*\((?P<tz>.+)\)'
|
||||
m = re.match(regex, timestr.strip())
|
||||
|
||||
if m is None:
|
||||
raise RuntimeError('Apparently the timestamp "{}" does not match the regex.'.format(timestr))
|
||||
|
||||
matches = m.groupdict()
|
||||
tz = matches['tz'].strip().upper()
|
||||
offset = None
|
||||
if tz == 'PDT':
|
||||
# EDT is UTC - 4, PDT is UTC - 7, so you need +7 to make it UTC
|
||||
offset = +7
|
||||
elif tz == 'PST':
|
||||
# EST is UTC - 5, PST is UTC - 8, so you need +8 to make it UTC
|
||||
offset = +8
|
||||
else:
|
||||
raise RuntimeError('Unknown timezone found: {}'.format(tz))
|
||||
|
||||
pm = matches['p'].replace('.', '') # a.m. -> am
|
||||
|
||||
current_time = datetime.datetime.utcnow()
|
||||
|
||||
# Kind of hacky.
|
||||
fmt = "{2}/{0[month]}/{0[day]} {0[hour]}:{0[minutes]} {1}".format(matches, pm, current_time.year)
|
||||
splatoon_time = datetime.datetime.strptime(fmt, '%Y/%m/%d %I:%M %p') + datetime.timedelta(hours=offset)
|
||||
|
||||
# check for new year
|
||||
if current_time.month == 12 and splatoon_time.month == 1:
|
||||
splatoon_time.replace(current_time.year + 1)
|
||||
|
||||
return splatoon_time
|
||||
|
||||
|
||||
async def get_splatnet_schedule(splatnet_cookie):
|
||||
cookies = {'_wag_session': splatnet_cookie}
|
||||
|
||||
|
||||
"""
|
||||
This is repeated 3 times:
|
||||
|
||||
<span class"stage-schedule"> ... </span> <--- figure out how to parse this
|
||||
<div class="stage-list">
|
||||
<div class="match-type">
|
||||
<span class="icon-regular-match"></span> <--- turf war
|
||||
</div>
|
||||
... <span class="map-name"> ... </span>
|
||||
... <span class="map-name"> ... </span>
|
||||
</div>
|
||||
<div class="stage-list">
|
||||
<div class="match-type">
|
||||
<span class="icon-earnest-match"></span> <--- ranked
|
||||
</div>
|
||||
... <span class="rule-description"> ... </span> <--- Splat Zones, Rainmaker, Tower Control
|
||||
... <span class="map-name"> ... </span>
|
||||
... <span class="map-name"> ... </span>
|
||||
</div>
|
||||
"""
|
||||
|
||||
schedule = []
|
||||
async with aiohttp.get(SPLATNET_SCHEDULE_URL, cookies=cookies, data={'locale':"en"}) as response:
|
||||
text = await response.text()
|
||||
root = etree.fromstring(text, etree.HTMLParser())
|
||||
stage_schedule_nodes = root.xpath("//*[@class='stage-schedule']")
|
||||
stage_list_nodes = root.xpath("//*[@class='stage-list']")
|
||||
|
||||
if len(stage_schedule_nodes)*2 != len(stage_list_nodes):
|
||||
raise RuntimeError("SplatNet changed, need to update the parsing!")
|
||||
|
||||
for sched_node in stage_schedule_nodes:
|
||||
r = Rotation()
|
||||
|
||||
start_time, end_time = sched_node.text.split("~")
|
||||
r.start = parse_splatnet_time(start_time)
|
||||
r.end = parse_splatnet_time(end_time)
|
||||
|
||||
tw_list_node = stage_list_nodes.pop(0)
|
||||
r.turf_maps = tw_list_node.xpath(".//*[@class='map-name']/text()")
|
||||
|
||||
ranked_list_node = stage_list_nodes.pop(0)
|
||||
r.ranked_maps = ranked_list_node.xpath(".//*[@class='map-name']/text()")
|
||||
r.ranked_mode = ranked_list_node.xpath(".//*[@class='rule-description']/text()")[0]
|
||||
|
||||
schedule.append(r)
|
||||
|
||||
return schedule
|
212
cogs/utils/paginator.py
Normal file
212
cogs/utils/paginator.py
Normal file
|
@ -0,0 +1,212 @@
|
|||
import asyncio
|
||||
import discord
|
||||
|
||||
class CannotPaginate(Exception):
|
||||
pass
|
||||
|
||||
class Pages:
|
||||
"""Implements a paginator that queries the user for the
|
||||
pagination interface.
|
||||
|
||||
Pages are 1-index based, not 0-index based.
|
||||
|
||||
If the user does not reply within 2 minutes then the pagination
|
||||
interface exits automatically.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
bot
|
||||
The bot instance.
|
||||
message
|
||||
The message that initiated this session.
|
||||
entries
|
||||
A list of entries to paginate.
|
||||
per_page
|
||||
How many entries show up per page.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
embed: discord.Embed
|
||||
The embed object that is being used to send pagination info.
|
||||
Feel free to modify this externally. Only the description,
|
||||
footer fields, and colour are internally modified.
|
||||
permissions: discord.Permissions
|
||||
Our permissions for the channel.
|
||||
"""
|
||||
def __init__(self, bot, *, message, entries, per_page=12):
|
||||
self.bot = bot
|
||||
self.entries = entries
|
||||
self.message = message
|
||||
self.author = message.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.paginating = len(entries) > per_page
|
||||
self.reaction_emojis = [
|
||||
('\N{BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.first_page),
|
||||
('\N{BLACK LEFT-POINTING TRIANGLE}', self.previous_page),
|
||||
('\N{BLACK RIGHT-POINTING TRIANGLE}', self.next_page),
|
||||
('\N{BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR}', self.last_page),
|
||||
('\N{INPUT SYMBOL FOR NUMBERS}', self.numbered_page ),
|
||||
('\N{BLACK SQUARE FOR STOP}', self.stop_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)
|
||||
else:
|
||||
self.permissions = self.message.channel.permissions_for(self.bot.user)
|
||||
|
||||
if not self.permissions.embed_links:
|
||||
raise CannotPaginate('Bot does not have embed links permission.')
|
||||
|
||||
def get_page(self, page):
|
||||
base = (page - 1) * self.per_page
|
||||
return self.entries[base:base + self.per_page]
|
||||
|
||||
async def show_page(self, page, *, first=False):
|
||||
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)
|
||||
|
||||
self.embed.set_footer(text='Page %s/%s (%s entries)' % (page, self.maximum_pages, len(self.entries)))
|
||||
|
||||
if not self.paginating:
|
||||
self.embed.description = '\n'.join(p)
|
||||
return await self.bot.send_message(self.message.channel, embed=self.embed)
|
||||
|
||||
if not first:
|
||||
self.embed.description = '\n'.join(p)
|
||||
await self.bot.edit_message(self.message, 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)
|
||||
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.bot.add_reaction(self.message, reaction)
|
||||
|
||||
async def checked_show_page(self, page):
|
||||
if page != 0 and page <= self.maximum_pages:
|
||||
await self.show_page(page)
|
||||
|
||||
async def first_page(self):
|
||||
"""goes to the first page"""
|
||||
await self.show_page(1)
|
||||
|
||||
async def last_page(self):
|
||||
"""goes to the last page"""
|
||||
await self.show_page(self.maximum_pages)
|
||||
|
||||
async def next_page(self):
|
||||
"""goes to the next page"""
|
||||
await self.checked_show_page(self.current_page + 1)
|
||||
|
||||
async def previous_page(self):
|
||||
"""goes to the previous page"""
|
||||
await self.checked_show_page(self.current_page - 1)
|
||||
|
||||
async def show_current_page(self):
|
||||
if self.paginating:
|
||||
await self.show_page(self.current_page)
|
||||
|
||||
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:
|
||||
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)))
|
||||
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)
|
||||
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__))
|
||||
|
||||
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)
|
||||
|
||||
async def go_back_to_current_page():
|
||||
await asyncio.sleep(60.0)
|
||||
await self.show_current_page()
|
||||
|
||||
self.bot.loop.create_task(go_back_to_current_page())
|
||||
|
||||
async def stop_pages(self):
|
||||
"""stops the interactive pagination session"""
|
||||
await self.bot.delete_message(self.message)
|
||||
self.paginating = False
|
||||
|
||||
def react_check(self, reaction, user):
|
||||
if user is None or user.id != self.author.id:
|
||||
return False
|
||||
|
||||
for (emoji, func) in self.reaction_emojis:
|
||||
if reaction.emoji == emoji:
|
||||
self.match = func
|
||||
return True
|
||||
return False
|
||||
|
||||
async def paginate(self):
|
||||
"""Actually paginate the entries and run the interactive loop if necessary."""
|
||||
await self.show_page(1, first=True)
|
||||
|
||||
while self.paginating:
|
||||
react = await self.bot.wait_for_reaction(message=self.message, check=self.react_check, timeout=120.0)
|
||||
if react is None:
|
||||
self.paginating = False
|
||||
try:
|
||||
await self.bot.clear_reactions(self.message)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
break
|
||||
|
||||
try:
|
||||
await self.bot.remove_reaction(self.message, react.reaction.emoji, react.user)
|
||||
except:
|
||||
pass # can't remove it so don't bother doing so
|
||||
|
||||
await self.match()
|
Loading…
Add table
Add a link
Reference in a new issue