我如何将pytube中的音频流传输到FFMPEG和discord.py,而无需事先下载和转换

2024-04-26 03:39:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我在一个小型服务器上安装了discord.py bot。我已经设置了一个音乐命令,可以从YouTube下载一首歌曲并将其输出到VC中。目前,该命令下载完整歌曲,将其转换,然后将其输出到VC中,但这个过程非常缓慢。我如何将音频直接流式传输到VC中?我愿意使用youtube_dl代替pytube3。我不太关心较小的代码优化,因为这只是我和一些朋友的一个小机器人

谢谢你的意见

@bot.command()
async def play(ctx, *song):
    if ctx.author.voice is None or ctx.author.voice.channel is None:
        await ctx.send("You aren't in a VC!")
        return
    print(song) #debugging
    os.system("rm music.mp3")
    ydl_opts = {
        'noplaylist': True,        
        'outtmpl': 'music',
        'postprocessors': [{
            'key': 'FFmpegExtractAudio',
            'preferredcodec': 'mp3',
            'preferredquality': '128',
        }],
    'format': '139',  
    }
    youtube = pytube.YouTube(str(song).strip("(,)'"))
    video = youtube.streams.filter(only_audio=True).first()
    await ctx.send("downloading")
    video.download(filename="music")
    await ctx.send("converting...")
    os.system("ffmpeg -i music.mp4 -map 0:a:0 -b:a 96k music.mp3")
    
    voice_channel = ctx.author.voice.channel
    vc = await voice_channel.connect()
    vc.play(discord.FFmpegPCMAudio('music.mp3'), after=lambda e: print('done', e))
    while vc.is_playing():
        await asyncio.sleep(1)
    await ctx.voice_client.disconnect()

Tags: sendsongyoutubeisbotchannelmusicawait
1条回答
网友
1楼 · 发布于 2024-04-26 03:39:49

您已经在使用youtube_dl(从ydl_opts变量判断)。您可以做的是:

  • 如果您没有安装youtube_dl(pip install youtube-dl
  • 安装请求(pip install requests
  • 提取视频信息:
    from youtube_dl import YoutubeDL
    from requests import get
    
    #Get videos from links or from youtube search
    def search(query):
        with YoutubeDL({'format': 'bestaudio', 'noplaylist':'True'}) as ydl:
            try: requests.get(arg)
            except: info = ydl.extract_info(f"ytsearch:{arg}", download=False)['entries'][0]
            else: info = ydl.extract_info(arg, download=False)
        return (info, info['formats'][0]['url'])
    
  • 让机器人加入频道:
    async def join(ctx, voice):
        channel = ctx.author.voice.channel
    
        if voice and voice.is_connected():
            await voice.move_to(channel)
        else:
            voice = await channel.connect() 
    
  • 播放视频:
    from discord import FFmpegPCMAudio
    from discord.ext import commands
    from discord.utils import get
    
    
    @bot.command()
    async def play(ctx, *, query):
        #Solves a problem I'll explain later
        FFMPEG_OPTS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
    
        video, source = search(query)
        voice = get(bot.voice_clients, guild=ctx.guild)
    
        await join(ctx, voice)
        await ctx.send(f'Now playing {info['title']}.')
    
        voice.play(FFmpegPCMAudio(source, **FFMPEG_OPTS), after=lambda e: print('done', e))
        voice.is_playing()
    
  • 要知道video变量包含什么,可以打印它
  • 但是,流式音频会导致一个已知的问题explained here。要解决这个问题,必须使用FFMPEG_OPTS变量。它会将机器人重新连接到源,这样它仍然能够流式传输视频,当这种情况发生时,您的终端中会出现一条您不必担心的奇怪消息
  • 请注意,没有错误管理,您必须自己进行

相关问题 更多 >