16

I am experimenting with making my own little discord bot that can get information from Twitch, but I'm stumped on how to make the bot loop and check for a condition.

I want the bot to loop a section of code every few seconds that checks if the specified twitch channel is live.


Code

import discord
from discord.ext import commands, tasks
from twitch import TwitchClient
from pprint import pformat


client = TwitchClient(client_id='<twitch token>')

bot = commands.Bot(command_prefix='$')

@bot.event
async def on_ready():
    print('We have logged in as {0.user}'.format(bot))

@bot.command()
async def info(ctx, username):
    response = await ctx.send("Querying twitch database...")
    try:
        users = client.users.translate_usernames_to_ids(username)
        for user in users:
            print(user.id)
            userid = user.id
        twitchinfo = client.users.get_by_id(userid)
        status = client.streams.get_stream_by_user(userid)
        if status == None:
            print("Not live")
            livestat = twitchinfo.display_name + "is not live"
        else:
            livestat = twitchinfo.display_name + " is " + status.stream_type
        responsemsg = pformat(twitchinfo) + "\n" + livestat
        await response.edit(content=responsemsg)
    except:
        await response.edit(content="Invalid username")

bot.run("<discord token>")

I want the bot to run the following code every 10 seconds, for example:

status = client.streams.get_stream_by_user(<channel id>)
if status == None:
     print("Not live")
     livestat = twitchinfo.display_name + "is not live"
else:
     livestat = twitchinfo.display_name + " is " + status.stream_type

I've tried using @tasks.loop(seconds=10) to try and make a custom async def repeat every 10 seconds but it didn't seem to work.

Any ideas?

Diggy.
  • 6,744
  • 3
  • 19
  • 38
sharp312
  • 183
  • 1
  • 2
  • 8

4 Answers4

24

The newer version of discord.py doesn't support client.command()

To achieve the same I used the following snippet

import discord
from discord.ext import tasks
client = discord.Client()
@tasks.loop(seconds = 10) # repeat after every 10 seconds
async def myLoop():
    # work


myLoop.start()

client.run('<your token>')
Lovesh Dongre
  • 1,294
  • 8
  • 23
  • 4
    for the myLoop.start() line I get the error : `RuntimeError: no running event loop` `sys:1: RuntimeWarning: coroutine 'Loop._loop' was never awaited` – bbrendon Dec 04 '22 at 22:28
  • 1
    @Brendon this is because all awaits need to happen inside an async function. Put `myLoop.start()` inside the async `on_ready` function and it'll work. – David Maness Feb 15 '23 at 23:03
8

This can be done like so:

async def my_task(ctx, username):
    while True:
        # do something
        await asyncio.sleep(10)

@client.command()
async def info(ctx, username):
    client.loop.create_task(my_task(ctx, username))

References:

Diggy.
  • 6,744
  • 3
  • 19
  • 38
5

This is the most proper way to implement background tasks.

from discord.ext import commands, tasks

bot = commands.Bot(...)

@bot.listen()
async def on_ready():
    task_loop.start() # important to start the loop

@tasks.loop(seconds=10)
async def task_loop():
    ... # this code will be executed every 10 seconds after the bot is ready

Check this for more info

Exenifix
  • 71
  • 1
  • 7
0

I struggled with this as well. The problem I ran into is that none of the examples online were complete. Here is one I came up with that uses @tasks.loop(seconds=10).


import discord
import os
from discord.ext import tasks
from dotenv import load_dotenv

intents = discord.Intents.all()
client = discord.Client(command_prefix="!", intents=intents)

load_dotenv()
token = os.getenv("DISCORD_TOKEN")
CHANNEL_ID = 1234

@client.event
async def on_ready():
    print(f"We have logged in as {client.user}")
    myloop.start()

@client.event
async def on_message(message):
    if message.author == client.user: 
        return

    if message.content.startswith("hi"):
        await message.channel.send("Hello!")

@tasks.loop(seconds=10)
async def myloop():
    channel = client.get_channel(CHANNEL_ID)
    await channel.send("Message")

client.run(token)
bbrendon
  • 416
  • 3
  • 8