Discord舞台频道音乐机器人无声音/单轨播放问题求助
问题描述
我复刻了一个音乐机器人,为了让它在舞台频道播放音乐,修改了join命令,将suppress设为False。
改动后的join命令代码
@commands.command(name="join", invoke_without_subcommand=True) async def _join(self, ctx: commands.Context): destination = ctx.author.voice.channel if ctx.voice_state.voice: await ctx.voice_state.voice.move_to(destination) return if ctx.author.voice.channel.type == discord.enums.ChannelType.stage_voice: ctx.voice_state.voice = await destination.connect() # await ctx.me.request_to_speak() await ctx.me.edit(suppress=False) else: ctx.voice_state.voice = await destination.connect()
play命令代码
async def _play(self, ctx: commands.Context, *, search: str): if search.__contains__("?list="): if not ctx.voice_state.voice: await ctx.invoke(self._join) async with ctx.typing(): playlist, playlistTitle = self._playlist(search) for _title, _link in playlist.items(): try: source = await YTDLSource.create_source( ctx, _link, loop=self.bot.loop ) except YTDLError as e: await ctx.send("リクエストの手続きにエラーが起きました:{}".format(str(e))) else: song = Song(source) await ctx.voice_state.songs.put(song) await ctx.send( f"**{playlistTitle}からの曲を`{playlist.__len__()}`件キューに追加されました**" ) else: async with ctx.typing(): try: source = await YTDLSource.create_source( ctx, search, loop=self.bot.loop ) except YTDLError as e: await ctx.send("リクエストの手続きにエラーが起きました:{}".format(str(e))) else: song = Song(source) if not ctx.voice_state.voice: await ctx.invoke(self._join) await ctx.voice_state.songs.put(song) await ctx.send("キューに追加されました {}".format(str(source)))
目前遇到两个问题:
- 使用
suppress=False时,机器人已成为舞台频道发言者,但完全无法播放音乐;普通语音频道工作正常。 - 改用
request_to_speak()替代suppress=False时,机器人仅能播放单轨,无法播放后续曲目。
原因分析与解决方案
一、suppress=False无法播放的原因
Discord舞台频道的发言权限逻辑中,直接修改suppress=False只是让机器人的发言状态显示为“未静音”,但没有真正获取到语音传输的底层权限。舞台频道的音频输出要求机器人处于“活跃发言”状态,单纯修改suppress属性无法触发Discord服务器的语音流权限分配,导致音频无法输出。
二、request_to_speak()只能播放单轨的原因
request_to_speak()是异步请求发言的方法,但机器人播放完一首曲目后,可能因为频道自动静音规则、播放结束时的状态重置等原因,导致下一首曲目播放时发言权限失效。另外原代码的播放逻辑中,没有在每首曲目开始前重新检查并确保机器人的发言状态。
解决方案
1. 正确处理舞台频道发言权限
放弃直接设置suppress=False,改用request_to_speak(),并且在每一首曲目开始播放前检查发言状态:
# 在播放单首歌的逻辑中添加(比如原代码的播放循环部分) if ctx.voice_state.voice.channel.type == discord.enums.ChannelType.stage_voice: if ctx.me.suppress: await ctx.me.request_to_speak() await asyncio.sleep(1) # 留给Discord服务器处理请求的时间
2. 修复播放循环的状态检查
找到原代码中处理歌曲播放循环的函数(通常类似play_next),添加发言状态校验:
async def play_next(self, ctx): song = await ctx.voice_state.songs.get() if song: # 检查舞台频道发言权限 if ctx.voice_state.voice.channel.type == discord.enums.ChannelType.stage_voice: if ctx.me.suppress: await ctx.me.request_to_speak() await asyncio.sleep(0.5) # 播放歌曲 ctx.voice_state.current = song ctx.voice_state.voice.play(song.source, after=lambda _: self.bot.loop.create_task(self.play_next(ctx))) await ctx.send(f"再生中: {song.source.title}") else: ctx.voice_state.current = None await ctx.voice_state.voice.disconnect()
3. 确认机器人权限配置
在Discord开发者后台,给机器人开启**「请求发言」权限**,同时确保机器人所在服务器角色拥有舞台频道的发言权限。
内容的提问来源于stack exchange,提问作者nyahm
相关产品推荐
相关产品推荐

