Tiktok-视频上传与发布完全

@TiktokAPI

Tiktok API 进阶:视频上传与发布完全指南

嗨,小伙伴们!

上次我们介绍了 Tiktok API 的基础知识,学习了如何进行授权和获取用户信息。

今天我们来聊一个更有趣的话题:如何通过 API 上传和发布视频到 Tiktok!

这可是很多内容创作者、营销团队梦寐以求的功能啊!

想象一下,你可以直接从自己的应用程序发布视频到 Tiktok,甚至可以批量上传、定时发布,是不是很酷?

那就开始今天的学习吧!

一、视频上传 API 概述

首先要明确一点,Tiktok 的视频上传 API 属于高级功能,需要特殊的权限申请。

不是所有开发者都能直接使用这个功能,你需要在 Tiktok 开发者平台申请开通视频上传权限。

申请步骤大致如下:

  1. 登录 Tiktok 开发者平台

  2. 进入你的应用设置页面

  3. 找到"权限申请"或"Features"部分

  4. 申请"Video Upload"权限,并说明你的用途

  5. 等待 Tiktok 团队审核(通常需要 1-3 个工作日)

获得权限后,你就可以开始使用视频上传 API 了。

二、视频上传流程

Tiktok 视频上传是一个多步骤的过程,主要包括以下步骤:

  1. 初始化上传会话
  2. 分片上传视频数据
  3. 完成上传并发布视频

下面我们详细介绍每个步骤。

1. 初始化上传会话

首先,我们需要调用 API 创建一个上传会话:

const axios = require('axios');
const fs = require('fs');
const path = require('path');

async function initVideoUpload(accessToken, videoFilePath) {
  // 获取视频文件大小
  const stats = fs.statSync(videoFilePath);
  const fileSizeBytes = stats.size;
  
  try {
    const response = await axios.post('https://open.tiktokapis.com/v2/video/init/', {
      source_info: {
        source: 'FILE_UPLOAD',
        video_size: fileSizeBytes,
        chunk_size: 1024 * 1024 * 5, // 5MB 分片大小
        total_chunk_count: Math.ceil(fileSizeBytes / (1024 * 1024 * 5))
      }
    }, {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      }
    });
    
    return response.data.data;
  } catch (error) {
    console.error('初始化视频上传失败:', error);
    throw error;
  }
}

初始化成功后,你会收到一个上传 ID 和上传 URL,用于后续的分片上传:

{
  "data": {
    "upload_id": "7094567890123456789",
    "upload_url": "https://upload.tiktokapis.com/video/",
    "chunk_size": 5242880
  }
}

2. 分片上传视频数据

对于大文件,我们需要将视频分成多个小块(chunk)上传,这样可以提高上传成功率,也支持断点续传:

async function uploadVideoChunk(uploadUrl, uploadId, chunkIndex, chunkData) {
  try {
    const response = await axios.post(`${uploadUrl}`, chunkData, {
      headers: {
        'Content-Type': 'application/octet-stream',
        'x-upload-id': uploadId,
        'x-chunk-index': chunkIndex,
      }
    });
    
    return response.data;
  } catch (error) {
    console.error(`上传视频分片 ${chunkIndex} 失败:`, error);
    throw error;
  }
}

async function uploadVideoFile(uploadInfo, videoFilePath) {
  const { upload_id, upload_url, chunk_size } = uploadInfo;
  const fileSize = fs.statSync(videoFilePath).size;
  const totalChunks = Math.ceil(fileSize / chunk_size);
  
  // 打开文件流
  const fileStream = fs.createReadStream(videoFilePath, { highWaterMark: chunk_size });
  
  let chunkIndex = 0;
  let uploadedChunks = [];
  
  return new Promise((resolve, reject) => {
    fileStream.on('data', async (chunk) => {
      // 暂停流,等待当前块上传完成
      fileStream.pause();
      
      try {
        console.log(`上传分片 ${chunkIndex + 1}/${totalChunks}...`);
        
        const result = await uploadVideoChunk(upload_url, upload_id, chunkIndex, chunk);
        uploadedChunks.push({
          index: chunkIndex,
          size: chunk.length
        });
        
        chunkIndex++;
        // 继续读取下一块
        fileStream.resume();
      } catch (error) {
        reject(error);
      }
    });
    
    fileStream.on('end', () => {
      console.log('所有分片上传完成');
      resolve({
        upload_id,
        total_chunks: totalChunks,
        uploaded_chunks: uploadedChunks
      });
    });
    
    fileStream.on('error', (error) => {
      reject(error);
    });
  });
}

这段代码会将视频文件分成多个块,然后逐一上传。

每个块上传成功后,我们会收到一个确认响应,表示该块已被服务器接收。

3. 完成上传并发布视频

所有分片上传完成后,我们需要调用 API 告诉 Tiktok 视频已经上传完成,并提供发布相关的信息:

async function completeVideoUpload(accessToken, uploadId, videoInfo) {
  try {
    const response = await axios.post('https://open.tiktokapis.com/v2/video/publish/', {
      upload_id: uploadId,
      video_info: {
        title: videoInfo.title,
        description: videoInfo.description,
        visibility: videoInfo.visibility || 'PUBLIC', // 可选: PUBLIC, FRIENDS, PRIVATE
        disable_comment: videoInfo.disableComment || false,
        disable_duet: videoInfo.disableDuet || false,
        disable_stitch: videoInfo.disableStitch || false,
        privacy_level: videoInfo.privacyLevel || 'PUBLIC',
        scheduled_publish_time: videoInfo.scheduledPublishTime || 0, // Unix 时间戳,0表示立即发布
        branded_content_toggle: videoInfo.brandedContentToggle || false
      }
    }, {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      }
    });
    
    return response.data.data;
  } catch (error) {
    console.error('完成视频上传失败:', error);
    throw error;
  }
}

发布成功后,我们会收到一个包含视频 ID 的响应:

{
  "data": {
    "video_id": "7094567890123456789",
    "share_url": "https://www.tiktok.com/@username/video/7094567890123456789"
  }
}

三、完整的视频上传示例

下面是一个完整的视频上传流程示例,整合了上面的所有步骤:

const express = require('express');
const multer = require('multer');
const fs = require('fs');
const path = require('path');
const axios = require('axios');

const app = express();
const upload = multer({ dest: 'uploads/' });

// 上传视频的路由
app.post('/upload-to-tiktok', upload.single('video'), async (req, res) => {
  try {
    // 获取上传的文件
    const videoFile = req.file;
    const accessToken = req.body.accessToken; // 从请求中获取访问令牌
    
    if (!videoFile) {
      return res.status(400).json({ error: '没有上传视频文件' });
    }
    
    // 准备视频信息
    const videoInfo = {
      title: req.body.title || '我的 TikTok 视频',
      description: req.body.description || '通过 API 上传的视频 #tiktok #api',
      visibility: req.body.visibility || 'PUBLIC'
    };
    
    // 1. 初始化上传
    console.log('初始化视频上传...');
    const uploadInfo = await initVideoUpload(accessToken, videoFile.path);
    
    // 2. 分片上传视频
    console.log('开始上传视频分片...');
    const uploadResult = await uploadVideoFile(uploadInfo, videoFile.path);
    
    // 3. 完成上传并发布
    console.log('完成视频上传并发布...');
    const publishResult = await completeVideoUpload(accessToken, uploadInfo.upload_id, videoInfo);
    
    // 清理临时文件
    fs.unlinkSync(videoFile.path);
    
    // 返回成功结果
    res.json({
      success: true,
      video_id: publishResult.video_id,
      share_url: publishResult.share_url
    });
    
  } catch (error) {
    console.error('上传视频到 TikTok 失败:', error);
    
    // 清理临时文件(如果存在)
    if (req.file && fs.existsSync(req.file.path)) {
      fs.unlinkSync(req.file.path);
    }
    
    res.status(500).json({
      success: false,
      error: error.message || '上传失败'
    });
  }
});

// 启动服务器
app.listen(3000, () => {
  console.log('服务器运行在 http://localhost:3000');
});

这个例子展示了如何创建一个 Web 服务,接收视频文件并上传到 Tiktok。

用户可以通过表单提交视频文件和相关信息,服务器会处理上传过程并返回结果。

四、高级功能:定时发布与草稿

Tiktok API 还支持一些高级功能,比如定时发布和保存为草稿:

1. 定时发布

你可以设置一个未来的时间点发布视频,这对于内容计划非常有用:

// 设置 24 小时后发布
const tomorrow = Math.floor(Date.now() / 1000) + 24 * 60 * 60;

const videoInfo = {
  title: '明天会发布的视频',
  description: '这个视频将在明天自动发布 #定时发布',
  scheduledPublishTime: tomorrow
};

// 其他代码不变...

2. 保存为草稿

你可以将视频上传后先保存为草稿,而不是直接发布:

const videoInfo = {
  title: '草稿视频',
  description: '这是一个草稿视频,需要手动发布',
  visibility: 'PRIVATE', // 设置为私密
  isDraft: true // 保存为草稿
};

// 调用完成上传 API 时,添加 draft 参数
async function completeVideoUploadAsDraft(accessToken, uploadId, videoInfo) {
  try {
    const response = await axios.post('https://open.tiktokapis.com/v2/video/publish/', {
      upload_id: uploadId,
      video_info: {
        // ... 其他字段
      },
      publish_mode: 'DRAFT' // 保存为草稿
    }, {
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      }
    });
    
    return response.data.data;
  } catch (error) {
    console.error('保存为草稿失败:', error);
    throw error;
  }
}

用户可以稍后在 Tiktok 应用中手动发布这些草稿视频。

五、视频上传的最佳实践

在实际开发中,有一些最佳实践可以帮助你更好地实现视频上传功能:

1. 视频格式和质量控制

Tiktok 对上传的视频有一定的格式和大小要求:

function checkVideoCompatibility(videoPath) {
  // 使用 ffprobe 或其他库获取视频信息
  const videoInfo = getVideoMetadata(videoPath);
  
  const recommendations = [];
  
  // 检查视频时长 (Tiktok 支持 5 秒至 10 分钟)
  if (videoInfo.duration < 5) {
    recommendations.push('视频过短,TikTok 要求至少 5 秒');
  } else if (videoInfo.duration > 600) {
    recommendations.push('视频过长,TikTok 一般支持最长 10 分钟');
  }
  
  // 检查分辨率 (推荐 1080x1920)
  if (videoInfo.width !== 1080 || videoInfo.height !== 1920) {
    recommendations.push(`当前分辨率 ${videoInfo.width}x${videoInfo.height},推荐使用 1080x1920`);
  }
  
  // 检查格式 (推荐 mp4)
  if (videoInfo.format !== 'mp4') {
    recommendations.push(`当前格式 ${videoInfo.format},推荐使用 mp4`);
  }
  
  return {
    isCompatible: recommendations.length === 0,
    recommendations
  };
}

在上传前检查视频的兼容性,可以提高上传成功率和视频质量。

2. 断点续传实现

对于大文件上传,断点续传是非常重要的功能:

async function resumableUpload(accessToken, videoFilePath, uploadInfo = null) {
  // 如果没有上传信息,初始化一个新的上传
  if (!uploadInfo) {
    uploadInfo = await initVideoUpload(accessToken, videoFilePath);
    
    // 保存上传信息到本地存储,用于断点续传
    saveUploadInfoToStorage(videoFilePath, uploadInfo);
  }
  
  try {
    // 上传视频文件
    const uploadResult = await uploadVideoFile(uploadInfo, videoFilePath);
    
    // 上传成功后,删除本地存储的上传信息
    removeUploadInfoFromStorage(videoFilePath);
    
    return uploadResult;
  } catch (error) {
    // 上传失败,保留上传信息,下次可以继续
    console.error('上传中断:', error);
    throw error;
  }
}

// 使用示例
app.post('/resumable-upload', async (req, res) => {
  const videoFilePath = req.body.videoPath;
  const accessToken = req.body.accessToken;
  
  // 检查是否有未完成的上传
  const savedUploadInfo = getUploadInfoFromStorage(videoFilePath);
  
  try {
    const result = await resumableUpload(accessToken, videoFilePath, savedUploadInfo);
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

这个实现会在上传开始时保存上传信息,如果上传中断,下次可以从断点继续。

3. 上传进度跟踪

对于用户体验,上传进度跟踪非常重要:

async function uploadVideoFileWithProgress(uploadInfo, videoFilePath, progressCallback) {
  const { upload_id, upload_url, chunk_size } = uploadInfo;
  const fileSize = fs.statSync(videoFilePath).size;
  const totalChunks = Math.ceil(fileSize / chunk_size);
  
  let chunkIndex = 0;
  let totalBytesUploaded = 0;
  
  // 打开文件流
  const fileStream = fs.createReadStream(videoFilePath, { highWaterMark: chunk_size });
  
  return new Promise((resolve, reject) => {
    fileStream.on('data', async (chunk) => {
      fileStream.pause();
      
      try {
        await uploadVideoChunk(upload_url, upload_id, chunkIndex, chunk);
        
        // 更新上传进度
        totalBytesUploaded += chunk.length;
        const progress = Math.min(100, Math.round((totalBytesUploaded / fileSize) * 100));
        
        // 调用进度回调
        progressCallback({
          chunkIndex,
          totalChunks,
          bytesUploaded: totalBytesUploaded,
          totalBytes: fileSize,
          percentage: progress
        });
        
        chunkIndex++;
        fileStream.resume();
      } catch (error) {
        reject(error);
      }
    });
    
    fileStream.on('end', () => {
      resolve({
        upload_id,
        total_chunks: totalChunks
      });
    });
    
    fileStream.on('error', (error) => {
      reject(error);
    });
  });
}

// 使用 WebSocket 向客户端推送进度
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws) => {
  console.log('WebSocket 客户端已连接');
  
  // 处理上传请求
  ws.on('message', async (message) => {
    const data = JSON.parse(message);
    
    if (data.type === 'upload') {
      try {
        // 初始化上传
        const uploadInfo = await initVideoUpload(data.accessToken, data.videoPath);
        
        // 上传视频,并发送进度更新
        await uploadVideoFileWithProgress(uploadInfo, data.videoPath, (progress) => {
          ws.send(JSON.stringify({
            type: 'progress',
            data: progress
          }));
        });
        
        // 完成上传
        const result = await completeVideoUpload(data.accessToken, uploadInfo.upload_id, data.videoInfo);
        
        // 发送成功消息
        ws.send(JSON.stringify({
          type: 'complete',
          data: result
        }));
      } catch (error) {
        // 发送错误消息
        ws.send(JSON.stringify({
          type: 'error',
          message: error.message
        }));
      }
    }
  });
});

通过 WebSocket,你可以实时向前端发送上传进度,提供更好的用户体验。

六、实用案例:批量视频上传工具

最后,让我们来看一个实用的案例:如何开发一个批量视频上传工具。

这对于内容创作者和营销团队特别有用:

const fs = require('fs');
const path = require('path');
const readline = require('readline');

// 批量上传功能
async function batchUploadVideos(accessToken, videoFolder, hashtagsFile = null) {
  // 读取文件夹中的所有视频
  const files = fs.readdirSync(videoFolder)
    .filter(file => ['.mp4', '.mov'].includes(path.extname(file).toLowerCase()))
    .map(file => path.join(videoFolder, file));
  
  if (files.length === 0) {
    console.log('没有找到视频文件');
    return;
  }
  
  console.log(`找到 ${files.length} 个视频文件`);
  
  // 读取话题标签(如果提供了文件)
  let hashtags = [];
  if (hashtagsFile && fs.existsSync(hashtagsFile)) {
    const content = fs.readFileSync(hashtagsFile, 'utf8');
    hashtags = content.split('\n')
      .map(line => line.trim())
      .filter(tag => tag.length > 0)
      .map(tag => tag.startsWith('#') ? tag : `#${tag}`);
      
    console.log(`从文件中加载了 ${hashtags.length} 个话题标签`);
  }
  
  // 随机选择话题标签的函数
  function getRandomHashtags(count = 5) {
    if (hashtags.length === 0) return '';
    
    const shuffled = [...hashtags].sort(() => 0.5 - Math.random());
    return shuffled.slice(0, Math.min(count, hashtags.length)).join(' ');
  }
  
  // 询问用户确认
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });
  
  const answer = await new Promise(resolve => {
    rl.question(`准备上传 ${files.length} 个视频文件,确认继续?(y/n) `, resolve);
  });
  
  rl.close();
  
  if (answer.toLowerCase() !== 'y') {
    console.log('操作已取消');
    return;
  }
  
  // 开始批量上传
  console.log('开始批量上传...');
  
  let successCount = 0;
  let failCount = 0;
  
  for (let i = 0; i < files.length; i++) {
    const videoFile = files[i];
    const fileName = path.basename(videoFile, path.extname(videoFile));
    
    console.log(`[${i+1}/${files.length}] 上传: ${fileName}`);
    
    try {
      // 准备视频信息
      const videoInfo = {
        title: fileName,
        description: `${fileName} ${getRandomHashtags()}`,
        visibility: 'PUBLIC'
      };
      
      // 上传流程
      const uploadInfo = await initVideoUpload(accessToken, videoFile);
      await uploadVideoFile(uploadInfo, videoFile);
      const result = await completeVideoUpload(accessToken, uploadInfo.upload_id, videoInfo);
      
      console.log(`✓ 上传成功: ${result.share_url}`);
      successCount++;
      
      // 避免频率限制,在每次上传之间等待一段时间
      if (i < files.length - 1) {
        console.log('等待 30 秒后继续下一个上传...');
        await new Promise(resolve => setTimeout(resolve, 30000));
      }
    } catch (error) {
      console.error(`✗ 上传失败: ${error.message}`);
      failCount++;
    }
  }
  
  console.log('\n批量上传完成!');
  console.log(`总计: ${files.length} 个视频`);
  console.log(`成功: ${successCount}`);
  console.log(`失败: ${failCount}`);
}

// 使用示例
batchUploadVideos(
  'YOUR_ACCESS_TOKEN',
  './videos',
  './hashtags.txt'
);

这个工具可以帮助内容创作者一次性上传多个视频,并自动添加话题标签,大大提高了工作效率。

七、总结与展望

今天我们深入学习了 Tiktok API 的视频上传功能,包括:

  1. 如何申请视频上传 API 权限

  2. 视频上传的完整流程(初始化、分片上传、完成发布)

  3. 高级功能(定时发布、保存草稿)

  4. 最佳实践(格式控制、断点续传、进度跟踪)

  5. 实用案例(批量上传工具)

通过这些功能,你可以为你的应用添加强大的 Tiktok 集成能力,自动化内容发布流程,提高工作效率。

不过需要注意的是,Tiktok API 的使用需要遵守平台的规则和政策,确保你的应用合规使用 API 功能。

在下一篇文章中,我们将探讨如何使用 Tiktok API 获取数据分析和洞察,帮助你更好地理解内容表现和受众特征。

如果你有什么问题或建议,欢迎在评论区留言交流~


学习资源

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值