基于instagram-private-api的Bot发布Instagram视频故事报错问询
问题排查与修复方案
报错根本原因
- 代码未区分图片/视频资源,所有读取到的文件都会传入sharp库执行JPEG格式转换,视频二进制流传入sharp会直接抛出异常,你看到的
error: undefined是错误栈未被完整打印导致的 - instagram-private-api的故事发布接口对图片、视频的传参要求不同,当前代码只适配了图片发布的参数逻辑
- 未做视频合规性校验,Instagram故事视频要求时长≤15秒、分辨率为9:16、编码为H.264、音频编码为AAC,不符合规范的视频也会触发发布失败
适配方案
第一步:新增依赖(可选,用于视频自动转码适配规范)
如果需要自动处理不符合规范的视频,先安装依赖:
npm install fluent-ffmpeg # 同时确保你的设备已安装ffmpeg环境,Windows可通过scoop install ffmpeg安装,Mac可通过brew install ffmpeg安装
第二步:修改核心发布逻辑
替换你代码中post函数里读取文件后的处理逻辑即可:
// 首先在文件顶部引入依赖 const ffmpeg = require('fluent-ffmpeg'); const { extname } = require('path'); // 以下是修改后的post函数 async function post() { logger.info("Post() called! ======================"); let postPromise = fsp.readdir(imgFolderPath) .then(filenames => { if (filenames.length < 1) throw new Error(`Folder ${imgFolderPath} is empty...`) logger.debug(`${filenames.length} files found in ${imgFolderPath}`); return filenames; }) .then(filenames => filenames.map(file => path.resolve(imgFolderPath + file))) .then(filenames => pickUnusedFileFrom(filenames, filenames.length)) .then(filename => { if (!dryrun) registerFileUsed(filename) // 把文件名和后缀一起传下去,方便后续判断类型 return { path: filename, ext: extname(filename).toLowerCase() } }) .then(async ({path, ext}) => { const buffer = await fsp.readFile(path); logger.debug("Read File Success "); let publishParams; // 图片处理逻辑 if (['.jpg', '.jpeg', '.png', '.webp'].includes(ext)) { const processedImg = await sharp(buffer).jpeg().toBuffer(); logger.debug("Sharp JPEG Success"); publishParams = { file: processedImg }; } // 视频处理逻辑 else if (['.mp4', '.mov'].includes(ext)) { // 如果不需要转码,直接传buffer即可 publishParams = { video: buffer }; // 如果需要自动转码适配Instagram规范,用下面这段替代上面的行 /* const tempPath = path.resolve(imgFolderPath, `temp_${Date.now()}.mp4`); await new Promise((resolve, reject) => { ffmpeg(path) .size('1080x1920') // 9:16分辨率 .duration(15) // 截断到15秒 .videoCodec('libx264') .audioCodec('aac') .output(tempPath) .on('end', resolve) .on('error', reject) .run(); }); const videoBuffer = await fsp.readFile(tempPath); await fsp.unlink(tempPath); // 删除临时文件 publishParams = { video: videoBuffer }; */ logger.debug("Video processing completed"); } else { throw new Error(`Unsupported file type: ${ext}`); } return publishParams; }) .then(async publishParams => { if (!dryrun) { return ig.publish.story(publishParams) .then(fb => logger.info("Posting successful!")) } else return logger.info("Data not sent, dryrun = true") }) .then(() => logger.info(`Next post scheduled for ${job.nextDates()}\n`)) // 修改错误打印逻辑,输出完整错误栈方便排查 .catch(err => { logger.error(err); logger.error(err.stack || 'No error stack available'); }) }
其他优化建议
- 可以把
imgFolderPath变量名改成更通用的resourceFolderPath,避免歧义 - 若不需要自动转码,确保你上传的视频本身符合Instagram故事的格式要求,避免发布失败
内容的提问来源于stack exchange,提问作者Shrimanta
相关产品推荐
相关产品推荐

