Greetings and welcome to part 4 of the DiscordPy tutorials. In this tutorial, we're going to add the functionality for our bot to share attachments. In this case, it will be an image of a graph of one of our user metrics, users online, over time.
In the previous tutorial, we covered how to schedule a task to run automatically every n
seconds. In our case, we did every 5, just to make sure it was working, and that's saving a CSV file of our users. That CSV file is called usermetrics.csv
and looks like:
1539367729,332,609,7588
1539367734,332,608,7589
1539367739,332,607,7590
1539367744,331,607,7590
1539367749,331,608,7589
1539367754,330,607,7590
1539367759,330,607,7590
1539367764,329,606,7591
1539367769,329,606,7591
1539367774,329,608,7589
1539367779,329,608,7589
1539367784,331,608,7589
1539367789,332,608,7589
1539367794,329,606,7591
1539367799,328,608,7589
1539367804,328,608,7589
1539367809,326,606,7591
1539367814,325,606,7591
Feel free to copy that and save it if you don't have your own metrics to test with or something.
First, we need to graph and save this stuff. Here's a quick script for that, using pandas and matplotlib (py -3.6 -m pip install pandas matplotlib
if you need them).
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
style.use("fivethirtyeight")
df = pd.read_csv("usermetrics.csv", names=['time', 'online', 'idle', 'offline'])
df['date'] = pd.to_datetime(df['time'],unit='s')
df['total'] = df['online'] + df['offline'] + df['idle']
df.drop("time", 1, inplace=True)
df.set_index("date", inplace=True)
print(df.head())
df['online'].plot()
plt.legend()
plt.show()
plt.savefig("online.png")
Good enough, and now we have the figure saved. We can take the above code, and add it to our background task, to make sure the image stays updated. Our code so far is:
import discord
import time
import asyncio
client = discord.Client()
token = open("token.txt", "r").read()
def community_report(guild):
online = 0
idle = 0
offline = 0
for m in guild.members:
if str(m.status) == "online":
online += 1
if str(m.status) == "offline":
offline += 1
else:
idle += 1
return online, idle, offline
async def user_metrics_background_task():
await client.wait_until_ready()
global sentdex_guild
sentdex_guild = client.get_guild(405403391410438165)
while not client.is_closed():
try:
online, idle, offline = community_report(sentdex_guild)
with open("usermetrics.csv","a") as f:
f.write(f"{int(time.time())},{online},{idle},{offline}\n")
await asyncio.sleep(5)
except Exception as e:
print(str(e))
await asyncio.sleep(5)
@client.event # event decorator/wrapper
async def on_ready():
global sentdex_guild
print(f"We have logged in as {client.user}")
@client.event
async def on_message(message):
global sentdex_guild
print(f"{message.channel}: {message.author}: {message.author.name}: {message.content}")
if "sentdebot.member_count()" == message.content.lower():
await message.channel.send(f"```py\n{sentdex_guild.member_count}```")
elif "sentdebot.logout()" == message.content.lower():
await client.close()
elif "sentdebot.community_report()" == message.content.lower():
online, idle, offline = community_report(sentdex_guild)
await message.channel.send(f"```Online: {online}.\nIdle/busy/dnd: {idle}.\nOffline: {offline}```")
client.loop.create_task(user_metrics_background_task())
client.run(token)
So now we modify the background task:
async def user_metrics_background_task():
await client.wait_until_ready()
global sentdex_guild
sentdex_guild = client.get_guild(405403391410438165)
while not client.is_closed():
try:
online, idle, offline = community_report(sentdex_guild)
with open("usermetrics.csv","a") as f:
f.write(f"{int(time.time())},{online},{idle},{offline}\n")
plt.clf()
df = pd.read_csv("usermetrics.csv", names=['time', 'online', 'idle', 'offline'])
df['date'] = pd.to_datetime(df['time'],unit='s')
df['total'] = df['online'] + df['offline'] + df['idle']
df.drop("time", 1, inplace=True)
df.set_index("date", inplace=True)
df['online'].plot()
plt.legend()
plt.savefig("online.png")
await asyncio.sleep(5)
except Exception as e:
print(str(e))
await asyncio.sleep(5)
Note I added the plt.clf()
, otherwise the bot will plot separate graphs of online user every time. Next, add the matplotlib and pandas imports:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
style.use("fivethirtyeight")
Now, we just want to add the online.png image to be shared, so, in the community report:
elif "sentdebot.community_report()" == message.content.lower():
online, idle, offline = community_report(sentdex_guild)
await message.channel.send(f"```Online: {online}.\nIdle/busy/dnd: {idle}.\nOffline: {offline}```")
file = discord.File("online.png", filename="online.png")
await message.channel.send("online.png", file=file)
Full code up to this point:
import discord
import time
import asyncio
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import style
style.use("fivethirtyeight")
client = discord.Client()
token = open("token.txt", "r").read()
def community_report(guild):
online = 0
idle = 0
offline = 0
for m in guild.members:
if str(m.status) == "online":
online += 1
if str(m.status) == "offline":
offline += 1
else:
idle += 1
return online, idle, offline
async def user_metrics_background_task():
await client.wait_until_ready()
global sentdex_guild
sentdex_guild = client.get_guild(405403391410438165)
while not client.is_closed():
try:
online, idle, offline = community_report(sentdex_guild)
with open("usermetrics.csv","a") as f:
f.write(f"{int(time.time())},{online},{idle},{offline}\n")
plt.clf()
df = pd.read_csv("usermetrics.csv", names=['time', 'online', 'idle', 'offline'])
df['date'] = pd.to_datetime(df['time'],unit='s')
df['total'] = df['online'] + df['offline'] + df['idle']
df.drop("time", 1, inplace=True)
df.set_index("date", inplace=True)
df['online'].plot()
plt.legend()
plt.savefig("online.png")
await asyncio.sleep(5)
except Exception as e:
print(str(e))
await asyncio.sleep(5)
@client.event # event decorator/wrapper
async def on_ready():
global sentdex_guild
print(f"We have logged in as {client.user}")
@client.event
async def on_message(message):
global sentdex_guild
print(f"{message.channel}: {message.author}: {message.author.name}: {message.content}")
if "sentdebot.member_count()" == message.content.lower():
await message.channel.send(f"```py\n{sentdex_guild.member_count}```")
elif "sentdebot.logout()" == message.content.lower():
await client.close()
elif "sentdebot.community_report()" == message.content.lower():
online, idle, offline = community_report(sentdex_guild)
await message.channel.send(f"```Online: {online}.\nIdle/busy/dnd: {idle}.\nOffline: {offline}```")
file = discord.File("online.png", filename="online.png")
await message.channel.send("online.png", file=file)
client.loop.create_task(user_metrics_background_task())
client.run(token)
Testing:
Woo hoo!