运行 youtube-dl 完成下载时的异步函数 (python)
Run an async function when youtube-dl finishes downloading (python)
我一直在使用 discord.py 重写为 python 编写音乐机器人。它通过 youtube-dl 下载视频并在语音聊天中播放。我一直在努力进行音乐扩展,最近意识到我完全忽略了一些东西。 youtube-dl 的 progress hooks
选项是同步的,而 discord.py 是异步的。 youtube-dl 在下载视频时生成一个子进程,而不是 运行 在当前线程上安装它,因此它不会挂起程序。下载完成后我需要 运行 的函数是协程,因为它是 discord.py
的一部分
TL;DR 当 youtube-dl 下载完成时,我需要 运行 协程
我知道这是可能的,我以前看过,但不太明白。
这是我目前的情况:
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
。由于 callback
继承了封闭 play
方法的范围,我们可以直接使用 self.bot.loop
:
def callback(d):
if d['status'] == 'finished':
self.bot.loop.create_task(ctx.send("Done!"))
print("Done!")
我一直在使用 discord.py 重写为 python 编写音乐机器人。它通过 youtube-dl 下载视频并在语音聊天中播放。我一直在努力进行音乐扩展,最近意识到我完全忽略了一些东西。 youtube-dl 的 progress hooks
选项是同步的,而 discord.py 是异步的。 youtube-dl 在下载视频时生成一个子进程,而不是 运行 在当前线程上安装它,因此它不会挂起程序。下载完成后我需要 运行 的函数是协程,因为它是 discord.py
TL;DR 当 youtube-dl 下载完成时,我需要 运行 协程
我知道这是可能的,我以前看过,但不太明白。
这是我目前的情况:
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
。由于 callback
继承了封闭 play
方法的范围,我们可以直接使用 self.bot.loop
:
def callback(d):
if d['status'] == 'finished':
self.bot.loop.create_task(ctx.send("Done!"))
print("Done!")