2020-03-20 12:22:13 +01:00
|
|
|
import datetime
|
2020-04-05 12:09:46 +02:00
|
|
|
import time
|
2020-03-20 12:22:13 +01:00
|
|
|
|
|
|
|
import discord
|
2020-04-09 15:07:34 +02:00
|
|
|
import humanize
|
2020-04-05 12:09:46 +02:00
|
|
|
import matplotlib.pyplot as np
|
2020-03-20 12:22:13 +01:00
|
|
|
|
2020-04-14 02:31:36 +02:00
|
|
|
import config
|
2020-03-20 12:22:13 +01:00
|
|
|
import utils.emojis
|
2020-04-14 02:31:36 +02:00
|
|
|
from config.config_types import factory
|
2020-03-20 12:22:13 +01:00
|
|
|
from modules.base import BaseClassPython
|
|
|
|
|
|
|
|
|
|
|
|
class MainClass(BaseClassPython):
|
|
|
|
name = "Perdu"
|
|
|
|
help = {
|
|
|
|
"description": "Module donnant les statistiques sur les perdants",
|
|
|
|
"commands": {
|
|
|
|
"`{prefix}{command}`": "Donne le classement des perdants de la semaine",
|
|
|
|
"`{prefix}{command} all`": "Donne le classement des perdants depuis toujours",
|
|
|
|
"`{prefix}{command} <nombre de jours>`": "Donne le classement des perdants sur la durée spécifiée",
|
2020-04-05 12:09:46 +02:00
|
|
|
"`{prefix}{command} stats [@mention]`": "Donne les statistiques d'un perdant.",
|
|
|
|
"`{prefix}{command} stats history": "Affiche un graphique avec le nombre de pertes."
|
2020-03-20 12:22:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, client):
|
|
|
|
super().__init__(client)
|
2020-04-14 02:31:36 +02:00
|
|
|
self.config.set({"channel": 0, "lost_role": 0, "min_delta": datetime.timedelta(minutes=26).total_seconds()})
|
|
|
|
self.config.register("channel", factory(config.config_types.Channel, self.client))
|
2020-03-21 22:44:34 +01:00
|
|
|
self.history = {}
|
2020-03-20 12:22:13 +01:00
|
|
|
|
|
|
|
async def on_message(self, message: discord.Message):
|
|
|
|
# Fill history
|
2020-03-21 22:43:14 +01:00
|
|
|
if message.author.bot:
|
|
|
|
return
|
2020-03-20 12:22:13 +01:00
|
|
|
if message.channel.id == self.config.channel:
|
|
|
|
if message.author.id not in self.history.keys():
|
|
|
|
# Add new user if not found
|
|
|
|
self.history.update(
|
|
|
|
{message.author.id: ([(message.created_at, datetime.timedelta(seconds=0)), ])}
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
# Update user and precompute timedelta
|
|
|
|
delta = message.created_at - self.history[message.author.id][-1][0]
|
|
|
|
if delta.total_seconds() >= self.config.min_delta:
|
|
|
|
self.history[message.author.id].append((message.created_at, delta))
|
|
|
|
await self.parse_command(message)
|
|
|
|
|
|
|
|
async def fill_history(self):
|
|
|
|
self.history = {}
|
|
|
|
async for message in self.client.get_channel(self.config.channel).history(limit=None):
|
|
|
|
if message.author.id not in self.history.keys():
|
|
|
|
# Add new user if not found
|
|
|
|
self.history.update({message.author.id: ([(message.created_at, datetime.timedelta(seconds=0)), ])})
|
|
|
|
else:
|
|
|
|
# Update user and precompute timedelta
|
|
|
|
delta = self.history[message.author.id][-1][0] - message.created_at
|
|
|
|
if delta.total_seconds() >= self.config.min_delta:
|
|
|
|
self.history[message.author.id].append((message.created_at, delta))
|
2020-04-09 14:05:39 +02:00
|
|
|
for user in self.history.keys():
|
|
|
|
self.history[user].sort(key=lambda x: x[0])
|
2020-03-20 12:22:13 +01:00
|
|
|
|
2020-04-05 12:09:46 +02:00
|
|
|
def get_top(self, top=10, since=datetime.datetime(year=1, month=1, day=1), with_user=None, only_users=None):
|
2020-03-20 12:22:13 +01:00
|
|
|
"""Return [(userid, [(date, delta), (date,delta), ...]), ... ]"""
|
|
|
|
# Extract only messages after until
|
2020-04-05 12:09:46 +02:00
|
|
|
if only_users is not None:
|
|
|
|
# Extract data for only_users
|
|
|
|
messages = []
|
|
|
|
for user in only_users:
|
|
|
|
try:
|
2020-04-09 14:05:39 +02:00
|
|
|
if self.history[user][-1][0] >= since:
|
2020-04-05 12:09:46 +02:00
|
|
|
messages.append((user, [message for message in self.history[user] if message[0] > since]))
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
messages.sort(key=lambda x: len(x[1]), reverse=True)
|
|
|
|
return messages
|
|
|
|
if with_user is None:
|
|
|
|
with_user = []
|
|
|
|
# Extract TOP top users, and with_users data
|
2020-03-20 12:22:13 +01:00
|
|
|
messages = []
|
|
|
|
for user in self.history.keys():
|
2020-04-09 14:05:39 +02:00
|
|
|
if self.history[user][-1][0] >= since:
|
2020-03-20 12:22:13 +01:00
|
|
|
messages.append((user, [message for message in self.history[user] if message[0] > since]))
|
|
|
|
messages.sort(key=lambda x: len(x[1]), reverse=True)
|
|
|
|
# Extract top-ten
|
2020-04-05 12:09:46 +02:00
|
|
|
saved_messages = messages[:min(top, len(messages))]
|
|
|
|
# Add with_user
|
|
|
|
saved_messages.extend([message for message in messages if message[0] in with_user])
|
|
|
|
return saved_messages
|
2020-03-20 12:22:13 +01:00
|
|
|
|
|
|
|
async def com_fill(self, message: discord.Message, args, kwargs):
|
2020-04-05 20:48:00 +02:00
|
|
|
if self.auth(message.author):
|
2020-03-20 12:22:13 +01:00
|
|
|
async with message.channel.typing():
|
|
|
|
await self.fill_history()
|
|
|
|
await message.channel.send("Fait.")
|
|
|
|
|
|
|
|
async def com_all(self, message: discord.Message, args, kwargs):
|
|
|
|
# Get all stats
|
|
|
|
top = self.get_top()
|
2020-04-09 15:07:34 +02:00
|
|
|
intervales = [sum(list(zip(*top[i][1]))[1], datetime.timedelta(0)) / len(top[i][1]) for i in range(len(top))]
|
2020-03-20 12:22:13 +01:00
|
|
|
embed_description = "\n".join(
|
|
|
|
f"{utils.emojis.write_with_number(i)} : <@{top[i][0]}> a **perdu {len(top[i][1])} fois** depuis la"
|
2020-04-09 15:07:34 +02:00
|
|
|
f" création du salon à en moyenne **"
|
|
|
|
f"{(str(intervales[i].days) + ' jours et' if intervales[i].days else '')} "
|
|
|
|
f"{str(int(intervales[i].total_seconds() % (24 * 3600) // 3600)) + ':' if intervales[i].total_seconds() > 3600 else ''}"
|
|
|
|
f"{int((intervales[i].total_seconds() % 3600) // 60)} "
|
|
|
|
f"{'heures' if intervales[i].total_seconds() > 3600 else 'minutes'} d'intervalle.**"
|
2020-03-20 12:22:13 +01:00
|
|
|
for i in range(len(top))
|
|
|
|
)[:2000]
|
|
|
|
await message.channel.send(embed=discord.Embed(title="G-Perdu - Tableau des scores",
|
|
|
|
description=embed_description,
|
2020-04-09 14:05:39 +02:00
|
|
|
color=self.config.color))
|
2020-03-20 12:22:13 +01:00
|
|
|
|
|
|
|
async def com_stats(self, message: discord.Message, args, kwargs):
|
2020-04-09 14:05:39 +02:00
|
|
|
# TODO: Finir sum
|
|
|
|
if not ((not False or (not False or not ("sum" in args))) or not True):
|
2020-04-05 12:09:46 +02:00
|
|
|
if message.mentions:
|
|
|
|
top = self.get_top(only_users=[mention.id for mention in message.mentions] + [message.author.id])
|
|
|
|
else:
|
|
|
|
# TOP 5 + auteur
|
|
|
|
top = self.get_top(top=5, with_user=[message.author.id])
|
|
|
|
dates = []
|
|
|
|
new_top = {}
|
|
|
|
for t in top:
|
|
|
|
for date, _ in t[1]:
|
|
|
|
dates.append(date)
|
|
|
|
dates.sort()
|
|
|
|
dates.append(datetime.datetime.today() + datetime.timedelta(days=1))
|
|
|
|
for t in top:
|
|
|
|
user = t[0]
|
|
|
|
new_top.update({user: ([dates[0]], [0])})
|
|
|
|
i = 0
|
|
|
|
for date, _ in t[1]:
|
|
|
|
while date < dates[i]:
|
|
|
|
new_top[user][0].append(dates[i])
|
|
|
|
new_top[user][1].append(new_top[user][1][-1])
|
|
|
|
i += 1
|
|
|
|
new_top[user][0].append(date)
|
|
|
|
new_top[user][1].append(new_top[user][1][-1] + 1)
|
|
|
|
|
|
|
|
to_plot = [t[1][1:] for t in new_top.values()]
|
|
|
|
np.xlabel("Temps", fontsize=30)
|
|
|
|
np.ylabel("Score", fontsize=30)
|
|
|
|
np.title("Évolution du nombre de perdu au cours du temps.", fontsize=40)
|
2020-04-09 14:05:39 +02:00
|
|
|
np.legend()
|
2020-04-05 12:09:46 +02:00
|
|
|
file_name = f"/tmp/{time.time()}.png"
|
|
|
|
np.savefig(file_name, bbox_inches='tight')
|
|
|
|
await message.channel.send(file=discord.File(file_name))
|
|
|
|
|
|
|
|
if "history" in args:
|
2020-04-09 14:05:39 +02:00
|
|
|
since = datetime.datetime(year=1, month=1, day=1)
|
2020-04-09 15:07:34 +02:00
|
|
|
debut_message = "la création du salon"
|
|
|
|
top = 5
|
2020-04-09 14:05:39 +02:00
|
|
|
if "s" in [k[0] for k in kwargs]:
|
|
|
|
try:
|
|
|
|
d = [k[1] for k in kwargs if k[0] == "s"][0]
|
|
|
|
since = datetime.datetime.now() - datetime.timedelta(days=float(d))
|
2020-04-09 15:07:34 +02:00
|
|
|
debut_message = humanize.naturalday(since.date(), format='le %d %b')
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
if "t" in [k[0] for k in kwargs]:
|
|
|
|
try:
|
|
|
|
top = int([k[1] for k in kwargs if k[0] == "t"][0])
|
2020-04-09 14:05:39 +02:00
|
|
|
except ValueError:
|
|
|
|
pass
|
2020-04-05 12:09:46 +02:00
|
|
|
# Si mention, alors uniquement les mentions
|
|
|
|
if message.mentions:
|
2020-04-09 14:05:39 +02:00
|
|
|
top = self.get_top(since=since,
|
2020-04-09 15:07:34 +02:00
|
|
|
only_users=[mention.id for mention in message.mentions])
|
2020-04-05 12:09:46 +02:00
|
|
|
else:
|
|
|
|
# TOP 5 + auteur
|
2020-04-09 15:07:34 +02:00
|
|
|
top = self.get_top(since=since, top=top, with_user=[message.author.id])
|
2020-04-05 12:09:46 +02:00
|
|
|
new_top = {}
|
|
|
|
for t in top:
|
|
|
|
c = 0
|
|
|
|
counts = []
|
|
|
|
dates = []
|
2020-04-09 14:05:39 +02:00
|
|
|
for date, _ in t[1]:
|
2020-04-05 12:09:46 +02:00
|
|
|
c += 1
|
|
|
|
counts.append(c)
|
|
|
|
dates.append(date)
|
|
|
|
new_top.update({t[0]: (dates, counts)})
|
|
|
|
np.figure(num=None, figsize=(25, 15), dpi=120, facecolor='w', edgecolor='k')
|
|
|
|
for user, (dates, counts) in new_top.items():
|
2020-04-09 14:05:39 +02:00
|
|
|
np.plot_date(dates, counts, linestyle='-', label=str(self.client.get_user(user).name))
|
2020-04-05 12:09:46 +02:00
|
|
|
np.xlabel("Temps", fontsize=30)
|
|
|
|
np.ylabel("Score", fontsize=30)
|
2020-04-09 14:05:39 +02:00
|
|
|
np.legend(fontsize=20)
|
2020-04-09 15:07:34 +02:00
|
|
|
np.title(f"Évolution du nombre de perdu au cours du temps depuis {debut_message}.", fontsize=35)
|
2020-04-05 12:09:46 +02:00
|
|
|
file_name = f"/tmp/{time.time()}.png"
|
|
|
|
np.savefig(file_name, bbox_inches='tight')
|
|
|
|
await message.channel.send(file=discord.File(file_name))
|
2020-03-20 12:22:13 +01:00
|
|
|
|
|
|
|
async def command(self, message, args, kwargs):
|
|
|
|
if message.mentions:
|
|
|
|
await self.com_stats(message, args, kwargs)
|
|
|
|
since = datetime.datetime.now() - datetime.timedelta(days=7)
|
|
|
|
if args[0]:
|
|
|
|
try:
|
|
|
|
since = datetime.datetime.now() - datetime.timedelta(days=float(args[0]))
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
top = self.get_top(10, since)
|
2020-04-09 15:07:34 +02:00
|
|
|
intervales = [sum(list(zip(*top[i][1]))[1], datetime.timedelta(0)) / len(top[i][1]) for i in range(len(top))]
|
2020-03-20 12:22:13 +01:00
|
|
|
embed_description = "\n".join(
|
2020-04-09 15:07:34 +02:00
|
|
|
f"{utils.emojis.write_with_number(i)} : <@{top[i][0]}> a **perdu {len(top[i][1])} fois** depuis "
|
|
|
|
f"{humanize.naturalday(since.date(), format='le %d %b')} à en moyenne **"
|
|
|
|
f"{(str(intervales[i].days) + ' jours et' if intervales[i].days else '')} "
|
|
|
|
f"{str(int(intervales[i].total_seconds() % (24 * 3600) // 3600)) + ':' if intervales[i].total_seconds() > 3600 else ''}"
|
|
|
|
f"{int((intervales[i].total_seconds() % 3600) // 60)} "
|
|
|
|
f"{'heures' if intervales[i].total_seconds() > 3600 else 'minutes'} d'intervalle.**"
|
2020-03-20 12:22:13 +01:00
|
|
|
for i in range(len(top))
|
|
|
|
)[:2000]
|
|
|
|
await message.channel.send(embed=discord.Embed(title="G-Perdu - Tableau des scores",
|
|
|
|
description=embed_description,
|
2020-04-05 13:09:16 +02:00
|
|
|
color=self.config.color))
|