Et bim V6

ET y'a les cogs mon p'tit tabarnak !
This commit is contained in:
Maël 2017-06-11 14:04:03 -04:00
commit 4fd8826d22
47 changed files with 2473 additions and 762 deletions

70
cogs/admin.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View file

Binary file not shown.

Binary file not shown.

58
cogs/utils/checks.py Normal file
View 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
View 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
View 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
View 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
View 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()