返回
LinkedIn API 视频分片上传问题排查与解决
javascript
2025-01-11 17:04:26
LinkedIn API 视频分片上传问题排查
使用 LinkedIn API 上传视频,分片上传是一个复杂的过程。 过程中任何一步出现偏差,都会导致视频上传后显示不完整,或者出现只有部分片段的情况。本篇文章将分析视频分片上传的常见问题,并给出解决方案。
问题:分片上传视频只显示一个随机片段
问题: 视频按照分片成功上传,服务端也成功接收了所有的分片 ID,最终发布的视频只显示了其中一个随机分片,而非完整视频。
原因分析: 问题不在于分片生成或单个分片的上传。 问题可能出在服务端接收和合并分片数据的方式上。以下列出一些常见的原因:
- 初始化上传信息错误: 初始化上传时,服务端可能没有正确记录需要合并的分片数量或顺序。当后续上传完成时,服务端缺少必要信息,无法将分片按正确顺序组装成完整的视频。
- 分片 ID 使用错误: 可能存在部分分片在上传完成后返回了错误的 ID,或者分片 ID 被意外更改,导致服务端在最终合并分片时找不到正确的分片。
- 上传顺序问题: 部分 API 要求分片必须按照特定顺序上传,如果你的代码没有严格按照这个顺序,服务端可能会出错。
- 服务端 bug: 也有可能是 LinkedIn 服务端自身的问题。尽管这种情况比较少见,但不能完全排除。
解决方案:检查上传流程
以下给出一些检查步骤和代码示例。
步骤 1:确认分片上传初始化逻辑正确
-
确认初始化上传 API 调用时传递了正确的参数。
-
检查响应数据,特别留意用于最终合并分片的 uploadToken 是否有效,video urn(比如 'urn:li:video:videoId')是否是正确的。
-
需要确保每次初始化上传都能获取到一个全新的且正确的 uploadToken 以及 video urn.
const response = await fetch( `${LN_API_BASE_URL}/${LN_API_VERSION}/videos?action=initializeUpload`, requestOptions // 请替换为你的初始化上传请求选项 ); const result = await response.json(); if(!result || !result.uploadToken || !result.video ){ throw new Error ("init upload failed") } // result 应包含uploadToken 和 video (video 是 'urn:li:video:videoId') const { uploadToken, video} = result; // 使用 uploadToken, video 进行后续上传分片操作
步骤 2:确认分片生成逻辑和路径
-
代码使用了 ffmpeg 处理视频分片。确保分片的起始时间和时长计算准确,并且正确设置了输出路径。
-
特别需要确认每次分片的开始时间和长度。 分片的起始时间,需要从
0
开始, 以分片长度递增,一直到整个视频的时长结束。
async function splitVideo(inputPath, chunkSize, outputDir) {
try {
await fs.mkdir(outputDir, { recursive: true });
const metadata = await new Promise((resolve, reject) => {
ffmpeg.ffprobe(inputPath, (err, metadata) => {
if (err) reject(err);
else resolve(metadata);
});
});
const duration = metadata.format.duration;
const chunkDuration = chunkSize / (metadata.format.size / duration);
const promises = [];
for (let startTime = 0, chunkIndex = 0; startTime < duration; startTime += chunkDuration, chunkIndex++) {
const outputPath = path.join(outputDir, `chunk_${chunkIndex}.mp4`);
// 注意 startTime 从 0 开始,并使用 chunkDuration 递增。
promises.push(processChunk(inputPath, startTime, chunkDuration, outputPath));
}
await Promise.all(promises);
console.log('Video split successfully');
} catch (error) {
console.error('Error splitting video:', error);
}
}
function processChunk(inputPath, startTime, chunkDuration, outputPath) {
return new Promise((resolve, reject) => {
ffmpeg(inputPath)
.setStartTime(startTime)
.setDuration(chunkDuration)
.output(outputPath)
.on('end', () => resolve())
.on('error', reject)
.run();
});
}
步骤 3:确认上传分片的顺序
- 严格按照 API 文档中要求的顺序上传分片。 某些 API 要求按照分片序号或者在返回的 instructions 中指定的顺序进行上传。
- 在
instructions.map
函数中需要确认正确获取分片ID
await splitVideoToTemp(fileName);
const uploadedChunksIds = [];
await Promise.all(
instructions?.map(async (instruction, index) => {
// 从instruction 对象中,根据你的API接口定义,正确拿到index.
// 如果不是数组 index 就根据instruction提供的特定顺序上传
const chunkName = `chunk_${index}.mp4`;
const outputPath = path.join(
process.cwd() + '/tmp/chunks',
chunkName
);
const blob = await getFileAsBlob(outputPath);
const result = uploadVideo(
instruction.uploadUrl, // 需要从 instruction 对象中拿到正确的 上传 url
blob,
params.pageAccessToken
);
const uploadedChunkId = await result;
// 注意:部分 API 接口返回的上传ID可能会不一样, 请检查接口定义,可能是在 `result.uploadedPartId`, 也可能直接是result. 请修改以下代码
if (uploadedChunkId) {
uploadedChunksIds.push(uploadedChunkId);
// delete file
await deleteFileFromTemp(outputPath);
}
})
);
步骤 4:检查 finalizeUpload 步骤
- 确保 finalizeUpload 步骤中使用的 video
urn
,uploadToken
以及上传的所有分片的 ID(uploadedPartIds
)都准确无误。const finalizeUploadRequest = { video: 'urn:li:video:videoId', // 请使用正确video urn uploadToken: '', //请使用正确uploadToken uploadedPartIds: [ ...ids ], // 分片的 ids,确保排序 }
步骤 5:加入错误重试机制
网络环境不稳定或 API 调用失败可能导致分片上传失败,增加重试逻辑。
async function uploadWithRetry(url, blob, maxRetries = 3) {
let retries = 0;
while (retries < maxRetries) {
try {
const result = await uploadVideo(url, blob); // 假设uploadVideo 包含了上传分片的逻辑
return result
} catch (error) {
console.error(`上传失败,正在重试...(第 ${retries + 1} 次)`);
retries++;
await new Promise(resolve => setTimeout(resolve, 1000 * retries )); // 重试之前添加延迟
}
}
throw new Error("分片上传失败, 已超出最大重试次数")
}
额外建议
- 在所有涉及 IO 操作的地方使用
try...catch
进行错误捕获。这有利于发现代码中可能存在的错误。 - 严格参照API文档进行代码编写。 仔细研读接口文档。
- 定期测试你的代码,尤其是在修改或者升级依赖之后。
- 对分片数据进行一些简单的校验,比如
blob.size
等属性是否符合你的预期.
通过对上述步骤进行仔细检查, 可以定位并解决问题。 分片上传视频需要严格按照 API 的要求,任何一步出现偏差都有可能导致上传失败或视频播放异常。