Search code examples
pythondiscord.pyschedule

Writing discord auto send messages


I need to send messages at specific time in discord chat.

I use both discord and schedule module

base code. I use the function send_schedule_message to send the message. from a list called schedule_messages, I parse the time and message I want to send. However, nothing is happening at the said time without errors.

schedule_messages = { "11:55": "Mine Clearence", "19:55": "Golemore", "01:49": "Daily reset" }
async def send_scheduled_message(message):
    channel_id = 1160338542329860116  
    channel = client.get_channel(channel_id)
    if channel is not None:
        await channel.send(message)
    else:
        print(f"Channel with ID {channel_id} not found.")

for time_str, message in schedule_messages.items():
    schedule.every().day.at(time_str, timezone('Europe/London')).do(asyncio.run, send_scheduled_message, message)

Solution

  • Your while True: loop at the end will not be run because the client.run will not return. It will hang until the bot disconnects.

    You can use discord.ext.tasks which is the official way of running background tasks.

    The documentation gives details on how to use a Cog approach. Since you seem to be using discord.Client rather than discord.ext.commands.Bot, you probably want to do something like this:

    import asyncio
    import schedule
    from discord import Client, Intents
    from discord.ext import tasks
    
    client = Client(intents=Intents.all())
    
    async def send_scheduled_message(message):
        channel_id = 1160338542329860116
        channel = client.get_channel(channel_id) or await client.fetch_channel(channel_id)
        if channel is not None:
            await channel.send(message)
        else:
            print(f"Channel with ID {channel_id} not found.")
    
    def run_async(coro, *args):
        loop = asyncio.get_running_loop()
        loop.create_task(coro(*args))
    
    # replace with your schedules
    schedule.every().second.do(run_async, send_scheduled_message, 'test this')
    
    @tasks.loop(seconds=1.0)
    async def loop():
        schedule.run_pending()
    
    @client.event
    async def on_ready():
        print('Starting schedule loop.')
        try:
            loop.start()
        except RuntimeError:
            # loop already started
            pass
    
    client.run('...')
    

    The run_async function is required because you cannot call asyncio.run when an event loop is already started by discord.py. It gets the current event loop and runs send_scheduled_message inside it.

    The loop function is the loop managed by discord.py. It's started in on_ready.