youtube-dl完成下载后,运行异步功能(python) [英] Run an async function when youtube-dl finishes downloading (python)

查看:183
本文介绍了youtube-dl完成下载后,运行异步功能(python)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在使用discord.py重写为python编写音乐bot。它通过youtube-dl下载视频并通过语音聊天播放。我一直在努力扩展音乐,最近发现我完全忽略了某些东西。 youtube-dl的进度钩子选项是同步的,而discord.py是异步的。 youtube-dl在下载视频时会生成一个子进程,而不是在当前线程上运行它,因此它不会挂起程序。下载完成后我需要运行的功能是协程,因为它是discord.py

I've been writing a music bot for python using the discord.py rewrite. It downloads videos via youtube-dl and plays them back in a voice chat. I've been working hard on a music extension, and recently realized I've completely overlooked something. The progress hooks option of youtube-dl is synchronous, while discord.py is async. youtube-dl spawns a subprocess when downloading a video rather than running it on the current thread, so it does not hang the program. The function I need to run on the completion of a download is a coroutine, as it is part of discord.py

TL的一部分; DR我需要在以下情况下运行协程youtube-dl下载完成

TL;DR I need to run a coroutine when a youtube-dl download finishes

我知道这是可能的,我之前看过,但不太了解。

I know this is possible, I've seen it done before, but don't quite understand it.

这是我到目前为止的内容:

Here's what I have so far:

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 <{url}>..")
    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])


推荐答案

从阻塞代码安排协程异步执行的最简单方法是 loop.create_task 。由于回调继承了封闭的 play 方法的范围,我们可以使用 self.bot.loop 直接:

The easiest way to schedule asynchronous execution of a coroutine from blocking code is loop.create_task. Since callback inherits the scope of the enclosing play method, we can use self.bot.loop directly:

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

这篇关于youtube-dl完成下载后,运行异步功能(python)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆