Discord.py中FFmpeg进程异常终止无音频播放问题求助
修复Discord音乐机器人在Replit上的FFmpeg返回码-9问题
错误原因分析
返回码-9对应SIGKILL信号,说明FFmpeg进程被系统强制终止。在Replit环境下,核心原因是平台内存/CPU资源限制,加上代码里的低效转码、阻塞逻辑进一步加剧了资源消耗,触发了平台的进程查杀机制。
具体修复步骤
1. 替换低效转码方式,弃用MoviePy
MoviePy封装层级高,转码时资源占用大,直接用FFmpeg命令行转码更轻量化:
# 替换原download函数中的MoviePy代码,改用subprocess调用FFmpeg import subprocess def download(yt): print("DOWNLOADING STREAM TO AUDIO.WEBM") stream = yt.streams.filter(only_audio=True, mime_type="audio/webm", abr="160kbps").order_by("abr").first() stream.download(filename="audio.webm") print("EXPORTING TO MP3") # 直接调用FFmpeg转码,参数优化资源占用 subprocess.run(["./ffmpeg", "-i", "audio.webm", "-vn", "-acodec", "libmp3lame", "-q:a", "2", "audio.mp3"], check=True) os.remove("audio.webm") print("DONE")
2. 优化异步逻辑,避免线程阻塞
原代码中thread.start()后立刻thread.join()等于同步执行,没有发挥线程优势,改用Discord.py适配的异步任务:
import asyncio # 把download改成异步函数,用asyncio.to_thread执行阻塞操作 async def download(yt): print("DOWNLOADING STREAM TO AUDIO.WEBM") stream = yt.streams.filter(only_audio=True, mime_type="audio/webm", abr="160kbps").order_by("abr").first() await asyncio.to_thread(stream.download, filename="audio.webm") print("EXPORTING TO MP3") await asyncio.to_thread(subprocess.run, ["ffmpeg", "-i", "audio.webm", "-vn", "-acodec", "libmp3lame", "-q:a", "2", "audio.mp3"], check=True) os.remove("audio.webm") print("DONE") # 在play命令中直接调用异步函数 await download(yt)
3. 修复语音频道连接逻辑
原代码在已连接时未正确获取现有客户端,且ctx.send遗漏await:
try: channel = ctx.author.voice.channel vc = ctx.voice_client if not vc: vc = await channel.connect() else: # 若已在其他频道,自动移动过去 if vc.channel != channel: await vc.move_to(channel) await ctx.send("已在语音频道,准备播放") except AttributeError: await ctx.send("你需要先加入一个语音频道!") return except Exception as e: await ctx.send(f"连接语音频道出错:{str(e)}") return
4. 给FFmpeg添加资源限制参数
播放时限制FFmpeg的线程数和日志输出,降低资源占用:
vc.play(discord.FFmpegPCMAudio( source="audio.mp3", executable="./ffmpeg", options="-threads 1 -loglevel error" ))
5. 修复错误捕获逻辑
去掉全局屏蔽错误的try/except,打印具体错误信息便于排查:
# 替换原外层空except except Exception as e: print(f"播放出错:{str(e)}") await ctx.send(f"播放出错:{str(e)}")
6. Replit环境额外优化
在Replit的replit.nix文件中添加FFmpeg系统依赖,无需本地副本:
{ pkgs }: { deps = [ pkgs.python310 pkgs.ffmpeg ]; }
之后代码中executable直接写"ffmpeg"即可,使用系统自带版本更稳定。
优化后的核心代码片段
@bot.command() async def play(ctx, arg): await ctx.send("Downloading...") try: yt = pytube.YouTube(arg) print("STREAM: "+str(yt.streams.filter(only_audio=True,mime_type="audio/webm",type="audio",abr="160kbps"))) async def download(yt): print("DOWNLOADING STREAM TO AUDIO.WEBM") stream = yt.streams.filter(only_audio=True, mime_type="audio/webm", abr="160kbps").order_by("abr").first() await asyncio.to_thread(stream.download, filename="audio.webm") print("EXPORTING TO MP3") await asyncio.to_thread(subprocess.run, ["ffmpeg", "-i", "audio.webm", "-vn", "-acodec", "libmp3lame", "-q:a", "2", "audio.mp3"], check=True) os.remove("audio.webm") print("DONE") await download(yt) try: channel = ctx.author.voice.channel vc = ctx.voice_client if not vc: vc = await channel.connect() else: if vc.channel != channel: await vc.move_to(channel) await ctx.send("已在语音频道,准备播放") except AttributeError: await ctx.send("你需要先加入一个语音频道!") return except Exception as e: await ctx.send(f"连接语音频道出错:{str(e)}") return vc.play(discord.FFmpegPCMAudio( source="audio.mp3", options="-threads 1 -loglevel error" )) await ctx.send(f"正在播放:{yt.title}") except Exception as e: print(f"整体出错:{str(e)}") await ctx.send(f"出错了:{str(e)}")
内容的提问来源于stack exchange,提问作者Bummbumm6
相关产品推荐
相关产品推荐

