Welcome to part 3 of the Discordpy tutorials. In this tutorial, we're going to cover timing actions that you might want to do every n seconds, minutes, hours...etc. In my case, I would like to start tracking various statistics from my server, saving them to later graph over time.
Code up to this point:
import discord
client = discord.Client()
token = open("token.txt","r").read()
@client.event # event decorator/wrapper
async def on_ready():
print(f"We have logged in as {client.user}")
@client.event
async def on_message(message):
print(f"{message.channel}: {message.author}: {message.author.name}: {message.content}")
sentdex_guild = client.get_guild(405403391410438165)
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 = 0
idle = 0
offline = 0
for m in sentdex_guild.members:
if str(m.status) == "online":
online += 1
if str(m.status) == "offline":
offline += 1
else:
idle += 1
await message.channel.send(f"```Online: {online}.\nIdle/busy/dnd: {idle}.\nOffline: {offline}```")
client.run(token)
At least for now, I am just going to track the online, offline, and idle numbers. Later, I might also add something to track messages per hour something like that too.
Because of this, I am going to move the community report code to its own function, since we're going to need that same code again.
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
Now the actual community_report
code is:
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}```")
Next, let's add a background task:
async def user_metrics_background_task():
await client.wait_until_ready()
global sentdex_guild
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)
Now, before our client.run
, we do:
client.loop.create_task(user_metrics_background_task())
I also have employed the use of global to share the guild value across the async methods.
Full code now is:
import discord
import asyncio
import time
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
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
sentdex_guild = client.get_guild(405403391410438165)
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)
Now, every 5 seconds, our bot saves some user stats. Now, what I'd like to do is collect these over time, then, replace the community_report
function to include some charts generated by our bot from these stats so we can see trends over time.