本文为您介绍如何使用视频点播服务端 Node.js SDK 将音频、视频、图片等媒资文件上传至视频点播服务。
媒资上传到视频点播中会产生存储费用,具体参见媒资存储计费。
视频点播服务端 SDK 封装了 ApplyUploadInfo - 获取上传地址和凭证和 CommitUploadInfo - 确认上传接口以及上传逻辑,您只需简单配置即可进行上传。
说明
const uploadMedia = async () => { try { const options = { SpaceName: "your target space name", // 空间名 FilePath: "your file path", // 绝对路径 FileName: "your target storage path", // 文件路径(可选)。您可根据业务需求自定义文件路径。设置 FileName, 当 FileName 相同时,有文件覆盖的风险;需要保证 FileName 不同。 FileExtension: "your file extension", // 文件后缀(可选)。以.开头,不超过 8 位。当您传入 FileExtension 时,不需要重复传入FileName 参数,视频点播将生成 32 位随机字符串,和您传入的 FileExtension 共同拼接成文件路径。 Functions: JSON.stringify([ { Name: "GetMeta" }, { Name: "Snapshot", Input: { SnapshotTime: 2.3, }, }, ]), CallbackArgs: "your callbackArgs" }; const res = await vodOpenapiService.UploadMedia(options); // do your work // ... } catch (err) { console.log(err); } };
视频点播服务端 SDK 封装了 URL 批量拉取上传接口,您只需简单配置即可进行上传。完整的上传流程请见服务端上传。
说明
const uploadMediaByUrl = async () => { try { const options = { SpaceName: "your space name", URLSets: [ { SourceUrl: "http://demourl/test1.mp4", FileName: "movie/test1.mp4", // 文件路径(可选)。设置 FileName, 当 FileName 相同时,有文件覆盖的风险;需要保证 FileName 不同。 FileExtension: ".mp4", // 文件后缀(可选)。以 . 开头,不超过 8 位。当您传入 FileExtension 时,不需要重复传入 FileName 参数,视频点播将生成 32 位随机字符串,和您传入的 FileExtension 共同拼接成文件路径。 }, { SourceUrl: "http://demourl/test2.mp4", FileName: "cartoon/test1.mp4", }, ], }; const res = await vodOpenapiService.UploadMediaByUrl(options); // do your work // ... } catch (err) { console.log(err); } };
const uploadMediaByStream = async () => { try { const options = { SpaceName: "your target space name", // 空间名 Content: "your file content", // 文件可读流 FileSize: "your file size", // 文件大小 FileName: "your target storage path", // 文件路径(可选)。您可根据业务需求自定义文件路径。设置 FileName, 当 FileName 相同时,有文件覆盖的风险;需要保证 FileName 不同。 FileExtension: "your file extension", // 文件后缀(可选)。以.开头,不超过 8 位。当您传入 FileExtension 时,不需要重复传入FileName 参数,视频点播将生成 32 位随机字符串,和您传入的 FileExtension 共同拼接成文件路径。 Functions: JSON.stringify([ { Name: "GetMeta" }, { Name: "Snapshot", Input: { SnapshotTime: 2.3, }, }, ]), CallbackArgs: "your callbackArgs", }; const res = await vodOpenapiService.UploadMedia(options); // do your work // ... } catch (err) { console.log(err); } };
视频点播服务端 SDK 封装了 ApplyUploadInfo - 获取上传地址和凭证和 CommitUploadInfo - 确认上传接口以及上传逻辑,您只需简单配置即可进行上传。
说明
const uploadMaterial = async () => { try { const options = { SpaceName: "your target space name", // 空间名 FilePath: "your local file path", // 目标文件的绝对路径 FileName: "your target storage path", // 文件路径(可选)。您可根据业务需求自定义文件路径 FileExtension: "your file extension", // 文件后缀(可选)。以 . 开头,不超过 8 位。当您传入 FileExtension 时,不需要重复传入 FileName 参数,视频点播将生成 32 位随机字符串,和您传入的 FileExtension 共同拼接成文件路径。 FileType: "your file type", Functions: JSON.stringify([ { Name: "GetMeta" }, { Name: "AddOptionInfo", Input: { Title: "素材测试名称", Tags: "test", Description: "素材测试,视频文件", Category: "video", Format: "MP4", RecordType: 2, }, }, ]), CallbackArgs: "your callbackArgs" }; const res = await vodOpenapiService.UploadMaterial(options); // do your work // ... } catch (err) { console.log(err); } };
Node.js SDK 支持断点续传功能,适用于大文件上传和网络不稳定的场景。当上传任务因网络异常或程序崩溃而中断时,SDK 能够从上次记录的断点(Checkpoint)处继续上传,提升上传的稳定性和效率。
断点信息会以 Checkpoint 文件的形式进行存储。您需要在上传时通过 checkpoint 参数指定一个文件路径,SDK 会自动创建和更新该文件以记录上传进度。您需要确保程序对该文件路径有读写权限。上传成功后,建议您主动删除此文件。在上传过程中,您还可以通过取消令牌 CancelToken 随时取消上传任务。
注意
在 UploadMedia 方法中配置以下参数来开启断点续传:
checkpoint:指定一个文件路径,SDK 将使用该文件来记录和读取上传进度。
partSize:设置分片大小(单位:字节)。
maxConcurrency:设置并发上传的分片数量。
onProgress:进度回调函数。您可以在此函数中获取上传百分比和实时的 checkpoint 对象,并将其持久化,以便在程序意外退出后用于恢复上传。
// 推荐在 onProgress 回调中实时保存 checkpoint,以便在程序崩溃后能恢复上传 const checkpointPath = './checkpoint.json'; const uploadResumableMedia = async () => { try { const res = await vodOpenapiService.UploadMedia({ SpaceName: 'your target space name', FilePath: 'your file path', checkpoint: checkpointPath, // 开启断点续传并指定 checkpoint 文件路径 partSize: 50 * 1024 * 1024, // 可选:设置分片大小为 50MB maxConcurrency: 5, // 可选:设置并发上传数为 5 onProgress: (percent, checkpoint) => { console.log(`上传进度: ${(percent * 100).toFixed(2)}%`); // 您可以在此处将 checkpoint 数据持久化存储(例如写入文件),以便在上传中断后恢复。 // fs.writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2)); }, onUploadEvent: (event) => { // 您可以监听上传过程中的详细事件,如分片初始化成功/失败、分片上传成功/失败等 console.log(`上传事件 Type: ${event.type}`); } }); console.log('上传成功', res); } catch (err) { console.log(err); } };
使用断点续传方式上传素材与断点续传方式上传音视频类似,只需在调用 UploadMaterial 方法时并传入相应的参数即可。
const checkpointPath = './material_checkpoint.json'; const uploadResumableMaterial = async () => { try { const res = await vodOpenapiService.UploadMaterial({ SpaceName: 'your target space name', FilePath: 'your local file path', FileType: 'image', // 指定文件类型,如 image, subtitle checkpoint: checkpointPath, // 开启断点续传并指定 checkpoint 文件路径 onProgress: (percent, checkpoint) => { console.log(`素材上传进度: ${(percent * 100).toFixed(2)}%`); // 建议在此处持久化 checkpoint } }); console.log('素材上传成功', res); } catch (err) { console.log(err); } };
上传任务中断后,您无需进行任何操作。SDK 会在下次执行上传操作时,自动检查 checkpoint 参数指定的文件是否存在。如果存在有效的进度记录,则会从该断点继续上传。以下是一个完整的示例,演示了如何加载已有的 checkpoint 文件来恢复上传,以及如何在上传成功后删除该文件。
const fs = require('fs'); const checkpointPath = './checkpoint.json'; const resumeUpload = async () => { let checkpoint = undefined; try { // 尝试从文件加载上一次的 checkpoint const content = fs.readFileSync(checkpointPath, 'utf-8'); checkpoint = JSON.parse(content); console.log('发现 checkpoint,将恢复上传...'); } catch (err) { console.log('未发现 checkpoint,将开始新的上传。'); } try { const res = await vodOpenapiService.UploadMedia({ SpaceName: 'your target space name', FilePath: 'your file path', checkpoint: checkpoint || checkpointPath, // 优先传入加载的 checkpoint 对象,否则传入文件路径 onProgress: (percent, newCheckpoint) => { const percentStr = (percent * 100).toFixed(2); console.log(`上传进度: ${percentStr}%`); // 实时保存 checkpoint,覆盖旧文件 fs.writeFileSync(checkpointPath, JSON.stringify(newCheckpoint, null, 2)); }, }); console.log('上传成功', res); // 上传成功后,建议删除 checkpoint 文件 fs.unlinkSync(checkpointPath); console.log('Checkpoint 文件已删除。'); } catch (err) { console.error('上传失败:', err.message); console.log('上传已中断,可从 checkpoint 文件恢复。'); } };
在上传过程中,您可以通过 axios.CancelToken 来取消上传任务。取消后,上传进度会保留在 checkpoint 文件中,后续仍可恢复上传。
const axios = require('axios'); const cancelUpload = async () => { const CancelToken = axios.CancelToken; const source = CancelToken.source(); const checkpointPath = './checkpoint_for_cancel.json'; const uploadPromise = vodOpenapiService.UploadMedia({ SpaceName: 'your target space name', FilePath: 'your file path', checkpoint: checkpointPath, cancelToken: source.token, // 传入 cancelToken onUploadEvent: (event) => { // 当上传被取消时,会触发 type 为 5 (UploadPartAborted) 的事件 console.log(`上传事件 Type: ${event.type}`); }, }); // 例如,在 2 秒后取消上传 setTimeout(() => { console.log('正在发起取消请求...'); source.cancel('用户主动取消上传'); }, 2000); try { await uploadPromise; } catch (err) { // 判断是否为取消操作导致的异常 if (axios.isCancel(err) || (err && err.message === '上传已取消')) { console.log('上传已成功取消。', err.message); console.log('进度已保存在 checkpoint 文件中,可以稍后恢复上传。'); } else { console.error('上传发生未知错误:', err); } } };
SDK 提供 onUploadEvent 回调函数,允许您监听上传生命周期中的各个关键事件。这对于详细的日志记录、错误诊断或监控非常有用。
const uploadWithEvents = async () => { try { const res = await vodOpenapiService.UploadMedia({ SpaceName: 'your target space name', FilePath: 'your file path', checkpoint: './checkpoint.json', onUploadEvent: (event) => { console.log(`[上传事件] 类型: ${event.type}`); // 可以根据事件类型进行不同的处理 if (event.partInfo) { console.log(` 分片信息: 序号 ${event.partInfo.partNumber}, 大小 ${event.partInfo.partSize}`); } if (event.err) { // 可以在分片失败时记录详细错误,便于排查 console.error(` 发生错误:`, event.err); } } }); } catch (err) { console.log(err); } };
onUploadEvent 回调函数接收的 event 对象中,type 字段标识了当前事件的类型。
事件类型 | 值 | 说明 |
|---|---|---|
| 1 | 初始化分片上传成功。 |
| 2 | 初始化分片上传失败。 |
| 3 | 单个分片上传成功。 |
| 4 | 单个分片上传失败。 |
| 5 | 上传任务被中止(例如通过 |
| 6 | 所有分片均已上传,服务端合并文件成功。 |
| 7 | 服务端合并文件失败。 |
每次事件回调都会提供一个包含以下字段的事件对象:
字段 | 类型 | 说明 |
|---|---|---|
|
| 事件的类型,详情见上表。 |
|
| 如果是失败或中止类型的事件,该字段会包含具体的错误对象。 |
|
| 本次上传所属的空间名称。 |
|
| 本次分片上传任务的唯一 ID。 |
|
| Checkpoint 文件的路径。 |
|
| 仅在与分片相关的事件中提供,包含分片的详细信息。
|
您可以通过配置上传事件通知及时获取上传的进展和状态,详细介绍请见上传事件通知。
您可以通过工作流实现上传后自动转码,详细介绍请见工作流。
音视频资源上传至视频点播服务之后,默认为未发布状态,此时无法获取到播放地址。因此在音视频播放前,您需要先修改音视频状态为已发布。具体操作请参见修改音视频发布状态。
FileName 参数设置了文件名称,但上传后控制台显示"未命名",为什么没有显示我设置的文件名称? 这是因为在视频点播服务中,FileName 参数实际上指的是文件路径(即媒资在存储桶中的唯一标识和存储位置),而不是用户可见的文件名称。如需设置控制台显示的文件名称,您需要通过上传功能函数设置 FileTitle 参数。详见上传功能函数说明。
参数 | 说明 |
|---|---|
FileType |
|
RecordType |
|
Category |
|
通过正确组合这三个参数,可确保文件上传至正确的域名并生成匹配的元数据。示例:
FileType 设为 media 或留空。RecordType 设为 1 或留空。Category 无需设置(仅当 RecordType=2 时生效)。FileType 设为 image(图片使用图片上传域名)。RecordType 设为 2(素材)。Category 设为 image(进一步指定为图片素材)。FileType 设为 object(非音视频/图片的文件类型)。RecordType 设为 2(素材)。Category 设为 subtitle(进一步指定为字幕素材)。说明
通过服务端 SDK 上传素材时,接口已默认设置 RecordType 为 2,用户无需再设置。
视频点播当前仅支持手动分类。您可在视频点播控制台指定空间内的分类管理页面创建分类并获取分类 ID,具体请见分类管理。
如果您使用客户端上传 SDK 进行上传,您需要在应用服务端通过 AK 和 SK 在本地签出临时上传 Token,不依赖外网。如希望同时生成多个临时上传 Token,您可以循环调用生成方法。更多信息,请见客户端上传。
// 可设置临时密钥过期时间(单位为毫秒),默认为 1h。 vodOpenapiService.GetUploadToken(); // 如下示例设置临时上传凭证过期时间为 30min。 vodOpenapiService.GetUploadToken(30 * 60 * 1000);
接口的请求参数和返回参数说明详见 QueryUploadTaskInfo。
const queryUploadTaskInfo = async () => { try { const options = { JobIds: "your job ids" }; const res = await vodOpenapiService.QueryUploadTaskInfo(options); // do your work // ... } catch (err) { console.log(err); } };
接口请求参数和返回参数说明详见 ApplyUploadInfo 及 CommitUploadInfo。
const uploadMedia = async () => { try { const options = { SpaceName: "your space name", FilePath: "your file path", // 绝对路径 Functions: JSON.stringify([ { Name: "GetMeta" }, { Name: "Snapshot", Input: { SnapshotTime: 2.3, }, }, ]), CallbackArgs: "your callbackArgs" }; const res = await vodOpenapiService.UploadMedia(options); // do your work // ... } catch (err) { console.log(err); } };
接口请求参数和返回参数说明详见 ApplyUploadInfo 及 CommitUploadInfo。
const uploadMaterial = async () => { try { const options = { SpaceName: "your space name", FilePath: "your file path", // 绝对路径 FileType: "your file type", Functions: JSON.stringify([ { Name: "GetMeta" }, { Name: "AddOptionInfo", Input: { Title: "素材测试名称", Tags: "test", Description: "素材测试,视频文件", Category: "video", Format: "MP4", RecordType: 2, }, }, ]), CallbackArgs: "your callbackArgs" }; const res = await vodOpenapiService.UploadMaterial(options); // do your work // ... } catch (err) { console.log(err); } };