有没有办法在异步中使用 youtube-dl
Is there a way to use youtube-dl in async
我有一个应用程序,我在其中使用 zmq
和 asyncio
与能够将带有 youtube-dl
的视频下载到服务器的客户端进行通信。我尝试将 await
添加到 youtube_dl
的下载功能,但它给了我一个错误,因为它不是协程。我现在的代码看起来像这样:
import asyncio
import youtube_dl
async def networking_stuff():
download = True
while True:
if download:
print("Received a request for download")
await youtube_to_mp3("https://www.youtube.com/watch?v=u9WgtlgGAgs")
download = False
print("Working..")
await asyncio.sleep(2)
async def youtube_to_mp3(url):
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}]
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
loop = asyncio.get_event_loop()
loop.create_task(networking_stuff())
loop.run_forever()
给出以下输出:
Received a request for download
[youtube] u9WgtlgGAgs: Downloading webpage
[youtube] u9WgtlgGAgs: Downloading video info webpage
[youtube] u9WgtlgGAgs: Extracting video information
[youtube] u9WgtlgGAgs: Downloading MPD manifest
[download] Destination: The Cardigans - My Favourite Game “Stone Version”-u9WgtlgGAgs.webm
[download] 100% of 4.20MiB in 00:03
[ffmpeg] Destination: The Cardigans - My Favourite Game “Stone Version”-u9WgtlgGAgs.mp3
Deleting original file The Cardigans - My Favourite Game “Stone Version”-u9WgtlgGAgs.webm (pass -k to keep)
Working..
Working..
....
Working..
Working..
而我希望 Working..
消息也打印在 youtube-dl
的消息之间。我是不是漏掉了什么,或者 async
/await
是不可能的? ffmpeg
阻塞了吗?如果是这样,我可以 运行 在 async
中下载而不转换为 mp3
还是使用线程是唯一的方法?
你说得对,不能简单地使任何函数异步。
您的问题假设 youtube-dl 需要 ffmpeg 才能工作。这不完全正确,它可以通过自己的方式下载单个流,AFAIK ffmpeg 仅用于将这些流(视频+音频+可能是字幕)混合到一个文件中。
如果您使用 ffmpeg,从性能的角度来看并没有太多优势,因为如果它是通过子进程使用的(最有可能的情况),那么至少有 1 个成熟的 进程 正在为完成这项工作而产生。与子进程的交互也可以以非阻塞方式完成——参见 https://docs.python.org/3/library/asyncio-subprocess.html,但无论如何,如果您的代码为每个任务生成一个进程,则在任何一种情况下都不会很好地扩展。
否则,可能(并且有一定意义)分叉 youtube-dl 并进行更改,以便所有网络操作都基于 asyncio。这可能是相当多的重构,但它应该是可行的。
关于您的代码:
首先,函数 youtube_to_mp3
根本不是异步的,因为没有可以执行 await …
表达式的代码路径。如果您从函数定义中删除 async
单词并从 await youtube_to_mp3("…
.[=18 中删除 await
,则代码 的含义根本不会改变 =]
其次,即使它是异步的,您也不会以允许 "parallel" 执行的方式使用它。 await
关键字的真正含义是:此任务 中的控制流 只有在等待的协程完成后才会继续。如果你需要在 "parallel" 中 运行 多个协程,你将不需要直接等待它们一个接一个。有几种并行 运行 协程的方法,例如,如果所有任务都在同一时刻已知(但它不看起来不像你的情况),或者使用即发即弃的方法(loop.create_task)。
我有一个应用程序,我在其中使用 zmq
和 asyncio
与能够将带有 youtube-dl
的视频下载到服务器的客户端进行通信。我尝试将 await
添加到 youtube_dl
的下载功能,但它给了我一个错误,因为它不是协程。我现在的代码看起来像这样:
import asyncio
import youtube_dl
async def networking_stuff():
download = True
while True:
if download:
print("Received a request for download")
await youtube_to_mp3("https://www.youtube.com/watch?v=u9WgtlgGAgs")
download = False
print("Working..")
await asyncio.sleep(2)
async def youtube_to_mp3(url):
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}]
}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
loop = asyncio.get_event_loop()
loop.create_task(networking_stuff())
loop.run_forever()
给出以下输出:
Received a request for download
[youtube] u9WgtlgGAgs: Downloading webpage
[youtube] u9WgtlgGAgs: Downloading video info webpage
[youtube] u9WgtlgGAgs: Extracting video information
[youtube] u9WgtlgGAgs: Downloading MPD manifest
[download] Destination: The Cardigans - My Favourite Game “Stone Version”-u9WgtlgGAgs.webm
[download] 100% of 4.20MiB in 00:03
[ffmpeg] Destination: The Cardigans - My Favourite Game “Stone Version”-u9WgtlgGAgs.mp3
Deleting original file The Cardigans - My Favourite Game “Stone Version”-u9WgtlgGAgs.webm (pass -k to keep)
Working..
Working..
....
Working..
Working..
而我希望 Working..
消息也打印在 youtube-dl
的消息之间。我是不是漏掉了什么,或者 async
/await
是不可能的? ffmpeg
阻塞了吗?如果是这样,我可以 运行 在 async
中下载而不转换为 mp3
还是使用线程是唯一的方法?
你说得对,不能简单地使任何函数异步。
您的问题假设 youtube-dl 需要 ffmpeg 才能工作。这不完全正确,它可以通过自己的方式下载单个流,AFAIK ffmpeg 仅用于将这些流(视频+音频+可能是字幕)混合到一个文件中。
如果您使用 ffmpeg,从性能的角度来看并没有太多优势,因为如果它是通过子进程使用的(最有可能的情况),那么至少有 1 个成熟的 进程 正在为完成这项工作而产生。与子进程的交互也可以以非阻塞方式完成——参见 https://docs.python.org/3/library/asyncio-subprocess.html,但无论如何,如果您的代码为每个任务生成一个进程,则在任何一种情况下都不会很好地扩展。
否则,可能(并且有一定意义)分叉 youtube-dl 并进行更改,以便所有网络操作都基于 asyncio。这可能是相当多的重构,但它应该是可行的。
关于您的代码:
首先,函数 youtube_to_mp3
根本不是异步的,因为没有可以执行 await …
表达式的代码路径。如果您从函数定义中删除 async
单词并从 await youtube_to_mp3("…
.[=18 中删除 await
,则代码 的含义根本不会改变 =]
其次,即使它是异步的,您也不会以允许 "parallel" 执行的方式使用它。 await
关键字的真正含义是:此任务 中的控制流 只有在等待的协程完成后才会继续。如果你需要在 "parallel" 中 运行 多个协程,你将不需要直接等待它们一个接一个。有几种并行 运行 协程的方法,例如,如果所有任务都在同一时刻已知(但它不看起来不像你的情况),或者使用即发即弃的方法(loop.create_task)。