Discord机器人发送YouTube MP4文件时触发413请求实体过大错误
Discord机器人发送YouTube MP4报错413 Payload Too Large的解决方法
错误原因
你遇到的413 Payload Too Large错误,本质是要发送的MP4文件大小超过了Discord的上传限制:
- 普通服务器频道的文件上传上限为8MB
- Nitro用户的服务器频道上限为50MB
而你的代码默认下载YouTube最高分辨率的MP4流,这类文件体积很容易超出上述限制。
解决方案
1. 下载更低分辨率的视频流
修改代码中的流筛选逻辑,指定下载更小分辨率的MP4,确保文件体积在Discord限制内。比如优先下载720p,没有则降级到480p:
@client.command() async def downloadmp4(ctx, link): yt = pytube.YouTube(link) # 先尝试获取720p的MP4流 video = yt.streams.filter(progressive=True, file_extension='mp4', resolution='720p').first() # 如果没有720p,降级到480p if not video: video = yt.streams.filter(progressive=True, file_extension='mp4', resolution='480p').first() # 若仍无匹配,取所有可用progressive流中分辨率最低的 if not video: video = yt.streams.filter(progressive=True, file_extension='mp4').order_by('resolution').asc().first() out_file = video.download(output_path='C:\\Users\\Ethan\\PycharmProjects\\YoutubeBot') await ctx.channel.send(file=discord.File(out_file)) os.remove(out_file)
注:原代码中的重命名步骤是多余的,因为progressive=True且file_extension='mp4'的流,下载后本身就是MP4格式,无需额外重命名。
2. 压缩视频文件
如果需要保留较高分辨率,可以用FFmpeg对下载后的视频进行压缩,降低文件体积后再发送。需要先安装FFmpeg并配置到系统环境变量中:
import subprocess import os @client.command() async def downloadmp4(ctx, link): yt = pytube.YouTube(link) video = yt.streams.filter(progressive=True, file_extension='mp4').order_by('resolution').desc().first() out_file = video.download(output_path='C:\\Users\\Ethan\\PycharmProjects\\YoutubeBot') # 压缩视频:CRF值越高体积越小(范围18-28,28为平衡值),音频码率设为128k compressed_file = os.path.splitext(out_file)[0] + '_compressed.mp4' subprocess.run([ 'ffmpeg', '-i', out_file, '-vcodec', 'libx264', '-crf', '28', '-acodec', 'aac', '-b:a', '128k', compressed_file ], check=True) await ctx.channel.send(file=discord.File(compressed_file)) # 删除临时文件 os.remove(out_file) os.remove(compressed_file)
3. 拆分长视频(针对时长较长的视频)
如果视频本身时长过长,即使压缩后仍超限制,可以用FFmpeg将视频拆分为多个片段,分别发送:
import subprocess import os @client.command() async def downloadmp4(ctx, link): yt = pytube.YouTube(link) video = yt.streams.filter(progressive=True, file_extension='mp4').order_by('resolution').desc().first() out_file = video.download(output_path='C:\\Users\\Ethan\\PycharmProjects\\YoutubeBot') # 每10分钟拆分一个片段(600秒) segment_duration = 600 subprocess.run([ 'ffmpeg', '-i', out_file, '-c', 'copy', '-map', '0', '-segment_time', str(segment_duration), '-f', 'segment', os.path.join(os.path.dirname(out_file), 'part_%03d.mp4') ], check=True) # 发送所有拆分后的片段 for part in sorted(os.listdir(os.path.dirname(out_file))): if part.startswith('part_') and part.endswith('.mp4'): part_path = os.path.join(os.path.dirname(out_file), part) await ctx.channel.send(file=discord.File(part_path)) os.remove(part_path) os.remove(out_file)
内容的提问来源于stack exchange,提问作者Etmann
相关产品推荐
相关产品推荐

