python - Discord.py 在不保存音频文件的情况下播放 Gtts
问题描述
我有这段代码可以将文本转换为音频并将其保存为 mp3,然后加入语音通道并播放音频文件
@commands.command()
async def tts(self, ctx, *, text):
sound = gtts(text=text, lang="en", slow=False).save("test.mp3")
channel=voice_channel.name
await ctx.send('User is in channel: '+ channel)
vc = await voice_channel.connect()
vc.play(discord.FFmpegPCMAudio('test.mp3'), after=print("Done"))
如果不将文本保存为语音并直接从 gtts 播放,我将如何做到这一点
解决方案
在gTTS 文档中,您可以找到直接播放声音的说明。在discord.py API 文档中,您会看到pipe
可以True
为该FFmpegPCMAudio
方法设置一个参数。
但是,该FFmpegPCMAudio
方法似乎无法正常工作,@Armster15 为此提供了一个针对 discord.py 问题的有效解决方案。您可以将他的代码复制到一个文件中(例如FFmpegPCMAudioGTTS.py
)并将类名重命名为FFmpegPCMAudioGTTS
以清楚起见,因为此方法不适用于普通流(仅适用于 gTTS)。
因此,您的代码可以变成:
from FFmpegPCMAudioGTTS import FFmpegPCMAudioGTTS
@commands.command()
async def tts(self, ctx, *, text):
sound = gtts(text=text, lang="en", slow=False)
sound_fp = BytesIO()
sound.write_to_fp(sound_fp)
channel = voice_channel.name
await ctx.send('User is in channel: ' + channel)
vc = await voice_channel.connect()
vc.play(FFmpegPCMAudioGTTS(sound_fp.read(), pipe=True), after=print("Done"))
FFmpegPCMAudioGTTS.py
import subprocess
import shlex
import io
from discord.opus import Encoder
import discord
class FFmpegPCMAudioGTTS(discord.AudioSource):
def __init__(self, source, *, executable='ffmpeg', pipe=False, stderr=None, before_options=None, options=None):
stdin = None if not pipe else source
args = [executable]
if isinstance(before_options, str):
args.extend(shlex.split(before_options))
args.append('-i')
args.append('-' if pipe else source)
args.extend(('-f', 's16le', '-ar', '48000', '-ac', '2', '-loglevel', 'warning'))
if isinstance(options, str):
args.extend(shlex.split(options))
args.append('pipe:1')
self._process = None
try:
self._process = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr)
self._stdout = io.BytesIO(
self._process.communicate(input=stdin)[0]
)
except FileNotFoundError:
raise discord.ClientException(executable + ' was not found.') from None
except subprocess.SubprocessError as exc:
raise discord.ClientException('Popen failed: {0.__class__.__name__}: {0}'.format(exc)) from exc
def read(self):
ret = self._stdout.read(Encoder.FRAME_SIZE)
if len(ret) != Encoder.FRAME_SIZE:
return b''
return ret
def cleanup(self):
proc = self._process
if proc is None:
return
proc.kill()
if proc.poll() is None:
proc.communicate()
self._process = None