【问题标题】:How would I stream audio from pytube to FFMPEG and discord.py without downloading and converting beforehand如何在不事先下载和转换的情况下将音频从 pytube 流式传输到 FFMPEG 和 discord.py
【发布时间】:2020-12-18 04:48:12
【问题描述】:

我在我的一个小型服务器中安装了一个 discord.py 机器人。我已经设置了一个从 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()

【问题讨论】:

    标签: python python-3.x discord discord.py python-asyncio


    【解决方案1】:

    您已经在使用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 变量。它会将机器人重新连接到源,因此它仍然能够流式传输视频,发生这种情况时,您的终端中会出现一条奇怪的消息,您无需担心。
    • 请注意,没有错误管理,您必须自己做。

    【讨论】:

    • 感谢您的回答!可悲的是在这一行:voice = get(self.bot.voice_clients, guild=ctx.guild),代码抛出了这个错误:NameError: name 'self' is not defined。我尝试在async def play(self, ctx, *, query): 中定义“自我”,但这引发了这个错误:AttributeError: 'str' object has no attribute 'guild'。我做错了吗?
    • 我的错,是voice = get(bot.voice_clients, guild=ctx.guild)(我拿了一部分代码忘记删除自己)
    • 使用requests(阻塞API)不会阻塞整个事件循环吗?另外,get 是在哪里定义的?
    • 使用requests 不会阻止任何内容。我在play中使用的get()方法来自discord.utils,我忘记在我的代码中导入了^^如果你想要单独的名字,你可以写from discord.utils import get as dget
    • 使用请求不会阻止任何事情 - 你能澄清一下吗? requests.get 是一个阻塞 API,所以它肯定会阻塞事件循环直到完成。
    猜你喜欢
    • 1970-01-01
    • 2020-03-07
    • 1970-01-01
    • 1970-01-01
    • 2015-09-16
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 2012-07-25
    相关资源
    最近更新 更多