Ejecuta una función asíncrona cuando youtube-dl termina de descargar (python)

He estado escribiendo un bot de música para python usando la reescritura discord.py. Descarga videos a través de youtube-dl y los reproduce en un chat de voz. He estado trabajando duro en una extensión musical, y recientemente me di cuenta de que había pasado por alto algo. La opción de progress hooks de youtube-dl es síncrona, mientras que discord.py es asíncrono. youtube-dl genera un subproceso al descargar un video en lugar de ejecutarlo en el subproceso actual, por lo que no bloquea el progtwig. La función que necesito ejecutar para completar una descarga es una guía, ya que forma parte de discord.py

TL; DR Tengo que ejecutar una rutina cuando finaliza una descarga de youtube-dl

Sé que esto es posible, lo he visto antes, pero no lo entiendo bien.

Esto es lo que tengo hasta ahora:

 def log(text): print(Style.BRIGHT + Fore.WHITE + '[' + Fore.RED + 'Music' + Fore.WHITE + '] ' + Style.RESET_ALL + text) def sync_config(): raw_config.seek(0) raw_config.write(json.dumps(config)) raw_config.truncate() lookup_opts = { "simulate": True, "quiet" : True, #TODO: make this part of config.json } if not os.path.exists("plugins/music"): log("Config does not exist! Creating it for you..") os.makedirs("plugins/music") if not os.path.exists("plugins/music/cache"): os.makedirs("plugins/music/cache") if not os.path.exists("plugins/music/config.json"): with open('plugins/music/config.json', 'w+') as f: f.write('{}') log('Created config.json') raw_config = open('plugins/music/config.json', 'r+') config = json.load(raw_config) class Music: def __init__(self, bot): self.bot = bot @commands.command(hidden=True) async def clearcache(self, ctx): if ctx.author.id in ctx.bot.config["admins"]: log("Cache cleared!") await ctx.message.add_reaction("✅") shutil.rmtree("plugins/music/cache") os.makedirs("plugins/music/cache") else: await ctx.send(ctx.bot.denied()) @commands.command() async def play(self, ctx, url): """Download and play a link from youtube""" message = await ctx.send(f"Downloading ..") with youtube_dl.YoutubeDL(lookup_opts) as ydl: try: info = ydl.extract_info(url) await message.edit(content=f"Downloading {info['title']}..") except: await ctx.send("An error occured downloading that video! Are you sure that URL is correct?") def callback(d): if d['status'] == 'finished': loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(ctx.send("Done!")) print("Done!") download_opts = { "format": 'm4a/bestaudio/best', "quiet" : True, #TODO: make this part of config.json 'progress_hooks': [callback], } with youtube_dl.YoutubeDL(download_opts) as ydl: ydl.download([url]) 

    La forma más fácil de progtwigr la ejecución asíncrona de una coroutina desde el código de locking es loop.create_task . Dado que la callback hereda el scope del método de play adjunto, podemos usar self.bot.loop directamente:

      def callback(d): if d['status'] == 'finished': self.bot.loop.create_task(ctx.send("Done!")) print("Done!")