我正在使用
discord.py
开发一个 Discord 机器人,作为该机器人的一部分,我的任务是创建音乐功能。我实际上已经这样做了,机器人将使用 pytube
模块播放歌曲。它通过下载最佳音频源,将其转换为 .wav
(以便 Discord 可以理解),然后打开该文件并通过语音客户端播放该文件,让语音通话中的每个人都能听到来实现这一点。这样做的问题是,由于必须在开始播放之前下载完整的音频,因此速度非常慢。这是当前的代码:
# Plays a Youtube object in the voice call.
async def play_youtube_object(self, yt:YouTube, interaction:discord.Interaction, voice_client):
try:
# Extract audio stream with highest audio bitrate
audio_stream = yt.streams.filter(file_extension="webm").order_by('abr').desc().first()
audio_filename = os.path.abspath(rf"./data/music cache/{yt.author}{hex(random.randint(1,999999))[2:]}")
audio_stream.download(filename=audio_filename+".webm")
# Convert from .webm to .wav
audio_f = moviepy.AudioFileClip(audio_filename+".webm")
audio_f.write_audiofile(audio_filename+".wav", fps=48000) # Discord requires 48kHz, 44.1kHz causes it to speed up by 8.125%.
remove_file(audio_filename + ".webm") # Remove the .webm since we're now done with it
# Open the downloaded audio file in binary mode and create a PCMAudio object which can be interpreted by discord
f = open(audio_filename+".wav", "rb")
source = PCMAudio(f)
# Play the audio
voice_client.play(source)
# Wait until the song is finished before ending the function
while voice_client.is_playing() or voice_client.is_paused():
await asyncio.sleep(1)
f.close()
except ...
我对此的潜在解决方案(如果可能的话)是直接从 YouTube 流式传输音频,将其转换为
PCMAudio
源并将其实时传送到 Discord。问题是,我不知道从哪里开始实施。是否可以?如果是这样,我应该从哪里开始研究呢?有一个模块可以帮助吗?
实际上,目标是获得接近即时的反馈:
pytube
YouTube
对象被解析为 play_youtube_object
子例程,然后音频立即开始在 Discord 中为用户播放(或者至少不超过 20)目前是第二次延迟)。
如有任何帮助或指点,请先感谢您! :D
解决了!感谢评论中的一些帮助,为我指明了正确的方向。使用
yt-dlp
并使用 ffmpeg
进行管道传输效果非常出色,消除了讨厌的延迟(现在大约 3 秒,一点也不差)。
这是工作代码,目前有点混乱,但我想在继续处理之前我应该先完成这篇文章:
async def play_youtube_url(self, url, interaction:discord.Interaction, voice_client):
ydl_opts = {
'format': 'bestaudio/best',
'quiet': True,
'noplaylist': True
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info(url, download=False)
audio_url = info_dict['url']
ffmpeg_options = {
'options': '-vn'
}
source = FFmpegPCMAudio(audio_url, **ffmpeg_options)
voice_client.play(source)
while voice_client.is_playing() or voice_client.is_paused():
await asyncio.sleep(1)
except Exception as e:
await interaction.followup.send(f"An error occured: {e}")
感谢
yt-dlp
,该程序将能够处理更多的音频源,只是不能处理具有 DRM 保护的音频源(如 Spotify),所以我可能需要看看是否可以找到解决方法,或者是否有人知道什么请评论:)。