Issue
I'm making a bot for a discord server and have a function that takes a bit of time to run. I want to add a spinning loading icon next to the status message like this Doing something: <spinning icon>
. It edits the original message to loop through these messages:
Doing something: \
Doing something: |
Doing something: /
Doing something: -
I tried using a separate thread to update the message like this:
async def loadingBar(ctx, message : discord.Message):
loadingMessage0 = "{0}: \\".format(message)
loadingMessage1 = "{0}: |".format(message)
loadingMessage2 = "{0}: /".format(message)
loadingMessage3 = "{0}: -".format(message)
index = 0
while True:
if(index == 0):
await message.edit(contents = loadingMessage0)
index = 1
elif(index == 1):
await message.edit(contents = loadingMessage1)
index = 2
elif(index == 2):
await message.edit(contents = loadingMessage2)
index = 3
elif(index == 1):
await message.edit(contents = loadingMessage1)
index = 0
farther down, the bot command that starts the process...
@bot.command()
async def downloadSong(ctx, url : str, songname : str):
#Other code that doesn't matter
message = await ctx.send("Downloading audio")
_thread = threading.Thread(target=asyncio.run, args=(loadingBar(ctx, message),))
_thread.start()
#Function that takes a while
#Some way to kill thread, never got this far
However, I get the error Task <Task pending coro=<loadingBar() running at bot.py:20> cb=[_run_until_complete_cb() at /Users/user/.pyenv/versions/3.7.3/lib/python3.7/asyncio/base_events.py:158]> got Future <Future pending> attached to a different loop
. I'm new to async programming and the discord libraries; Is there a better way to do this and if not what am I doing wrong?
Solution
Firstly, you should add a delay between iterations inside the while loop, use asyncio.sleep
for this.
Secondly - asyncio and threading doesn't really work together, there's also no point in using threading here since it defeats the whole purpose of asyncio, use asyncio.create_task
to run the coroutine "in the background", you can asign it to a variable and then call the cancel
method to stop the task.
import asyncio
async def loadingBar(ctx, message : discord.Message):
loadingMessage0 = "{0}: \\".format(message)
loadingMessage1 = "{0}: |".format(message)
loadingMessage2 = "{0}: /".format(message)
loadingMessage3 = "{0}: -".format(message)
index = 0
while True:
if(index == 0):
await message.edit(contents = loadingMessage0)
index = 1
elif(index == 1):
await message.edit(contents = loadingMessage1)
index = 2
elif(index == 2):
await message.edit(contents = loadingMessage2)
index = 3
elif(index == 1):
await message.edit(contents = loadingMessage1)
index = 0
await asyncio.sleep(1) # you can edit the message 5 times per 5 seconds
@bot.command()
async def downloadSong(ctx, url : str, songname : str):
message = await ctx.send("Downloading audio")
task = asyncio.create_task(loadingBar(ctx, message)) # starting the coroutine "in the background"
# Function that takes a while
task.cancel() # stopping the background task
Answered By - Łukasz Kwieciński
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.