How do I create a custom cycling status in discord.py?

Tags: , , ,



I have a discord bot that I’m using to learn how to use the API and to practise my python knowledge. I’m trying to create a system that randomly chooses a status and applies it then waits a short time, currently 10 minutes, then continue like that infinitely until the bot is shutdown. Currently, I have the loop in my on_ready() function but the bot shuts down after a short time (less than 10 minutes, around 2-3) and I can’t figure out why. The current code is this:

@client.event
async def on_ready():
  print("We have logged in as {0.user}".format(client))
  infiniteTime = 1
  while infiniteTime != 20:
    statusType = random.randint(0, 1)
    if statusType == 0:
      statusNum = random.randint(0, 10)
      await client.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.playing, name=playingStatus[statusNum]))
    else:
      statusNum = random.randint(0, 10)
      await client.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.watching, name=watchingStatus[statusNum]))
    time.sleep(600)

watchingStatus and listeningStatus are 1D arrays with 11 strings in. Any assistance/feedback is appreciated as I’m new to the API. Cheers!

ETA: Should probably clarify that I’ve realised that having the code in the on_ready() function means that it never ends and so can’t do anything else. I’m asking because I don’t know why the bot shuts-down on Discord’s end without me stopping the code and I don’t know where else I should put this loop as I’m new to this async/await system and the way the API functions.

Answer

The place where you are trying to change the status of the bot is correct, the problem is the way of trying to create this loop is stopping your bot from working, as time.sleep is not suitable for an asynchronous library such as discord.py. Instead you can use asyncio.sleep().

You could do something like this:

import asyncio

@client.event
async def on_ready():
  # ...
  # Here goes your code for on_ready()
  # ...
  while True:
    statusType = random.randint(0, 1)
    if statusType == 0:
      statusNum = random.randint(0, 10)
      await client.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.playing, name=playingStatus[statusNum]))
    else:
      statusNum = random.randint(0, 10)
      await client.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.watching, name=watchingStatus[statusNum]))
    asyncio.sleep(600)

Another way of doing this would be using discord.ext.tasks, which are functions defined to be running background tasks like the one you want to achieve.

from discord.ext import commands, tasks
import asyncio

# Your code here

@loop(seconds=600)
async def status_change():
    # ...
    # Some code to define playingStatus and watchingStatus arrays
    # ...
    statusType = random.randint(0, 1)
    if statusType == 0:
      statusNum = random.randint(0, 10)
      await client.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.playing, name=playingStatus[statusNum]))
    else:
      statusNum = random.randint(0, 10)
      await client.change_presence(status=discord.Status.online, activity=discord.Activity(type=discord.ActivityType.watching, name=watchingStatus[statusNum]))

status_change.before_loop(client.wait_until_ready())    
status_change.start()
client.run("TOKEN")

References:



Source: stackoverflow