Videos: insert

将视频上传到 YouTube,并可选择设置视频的元数据。

此方法支持媒体上传。 上传的文件必须符合以下限制条件:

  • 文件大小上限: 256GB
  • 接受的媒体 MIME 类型: video/*、application/octet-stream

配额影响: 每天 100 次调用。调用此方法在“视频上传”配额存储桶中的 配额费用 为 1 个单位。

常见应用场景

请求

HTTP 请求

POST https://www.googleapis.com/upload/youtube/v3/videos

授权

此请求需要获得以下至少一个范围的授权(详细了解身份验证和授权)。

范围
https://www.googleapis.com/auth/youtube.upload
https://www.googleapis.com/auth/youtube
https://www.googleapis.com/auth/youtubepartner
https://www.googleapis.com/auth/youtube.force-ssl

参数

下表列出了此查询支持的参数。列出的所有参数都是查询参数。

参数
必需参数
part string
part 参数在此操作中有两个用途。它用于标识写入操作将设置的属性,以及 API 响应将包含的属性。

请注意,并非所有部分都包含在插入或更新视频时可以设置的属性。例如,statistics 对象封装了 YouTube 为视频计算的统计信息,不包含您可以设置或修改的值。如果参数值指定了不包含可变值的 part,该 part 仍将包含在 API 响应中。

以下列表包含您可以包含在参数值中的 part 名称:
  • brandPartner
  • contentDetails
  • fileDetails
  • id
  • liveStreamingDetails
  • localizations
  • paidProductPlacementDetails
  • player
  • processingDetails
  • recordingDetails
  • snippet
  • statistics
  • status
  • suggestions
  • topicDetails
可选参数
notifySubscribers boolean
notifySubscribers 参数用于指明 YouTube 是否应向订阅了视频频道的用户发送有关新视频的通知。参数值 True 表示系统会向订阅者通知新上传的视频。不过,上传大量视频的频道所有者可能更愿意将该值设置为 False,以避免向频道的订阅者发送有关每个新视频的通知。默认值为 True。
onBehalfOfContentOwner string
此参数只能在经过适当授权的请求中使用。注意: 此参数仅供 YouTube 内容合作伙伴使用。

onBehalfOfContentOwner 参数表示请求的授权凭据标识的是代表参数值中指定的内容所有者行事的 YouTube 内容管理系统 (CMS) 用户。此参数适用于拥有和管理许多不同 YouTube 频道的 YouTube 内容合作伙伴。它允许内容所有者进行一次身份验证,即可访问其所有视频和频道数据,而无需为每个频道提供身份验证凭据。用户进行身份验证时使用的 CMS 账号必须与指定的 YouTube 内容所有者相关联。
onBehalfOfContentOwnerChannel string
此参数只能在经过适当授权的请求中使用。此参数只能在经过适当授权的请求中使用。注意: 此参数仅供 YouTube 内容合作伙伴使用。

onBehalfOfContentOwnerChannel 参数用于指定要向其添加视频的频道的 YouTube 频道 ID。当请求为 onBehalfOfContentOwner 参数指定值时,此参数是必需的,并且只能与该参数一起使用。此外,请求必须使用与 onBehalfOfContentOwner 参数指定的内容所有者相关联的 CMS 账号进行授权。最后,onBehalfOfContentOwnerChannel 参数值指定的频道必须与 onBehalfOfContentOwner 参数指定的内容所有者相关联。

此参数适用于拥有和管理许多不同 YouTube 频道的 YouTube 内容合作伙伴。它允许内容所有者进行一次身份验证,即可代表参数值中指定的频道执行操作,而无需为每个单独的频道提供身份验证凭据。

请求正文

在请求正文中提供视频资源。 对于该资源:

  • 您可以为以下属性设置值:

    • snippet.title
    • snippet.description
    • snippet.tags[]
    • snippet.categoryId
    • snippet.defaultLanguage
    • localizations.(key)
    • localizations.(key).title
    • localizations.(key).description
    • status.embeddable
    • status.license
    • status.privacyStatus:如果您未为此属性指定值,则上传的视频的隐私状态默认为 public。某些上传可能会根据创作者账号设置默认为 private,如 YouTube 帮助中心 中所述。从未经身份验证的 API 项目上传的视频不受限于私享观看模式。
    • status.publicStatsViewable
    • status.publishAt
    • status.selfDeclaredMadeForKids
    • status.containsSyntheticMedia
    • recordingDetails.recordingDate

响应

如果成功,此方法会在响应正文中返回视频资源。

示例

注意: 以下代码示例可能未涵盖所有受支持的编程语言。如需查看受支持的语言列表,请参阅客户端库文档。

Go

此代码示例调用 API 的 videos.insert 方法,将视频上传到与请求关联的频道。

此示例使用 Go 客户端库。

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"

	"google.golang.org/api/youtube/v3"
)

var (
	filename    = flag.String("filename", "", "Name of video file to upload")
	title       = flag.String("title", "Test Title", "Video title")
	description = flag.String("description", "Test Description", "Video description")
	category    = flag.String("category", "22", "Video category")
	keywords    = flag.String("keywords", "", "Comma separated list of video keywords")
	privacy     = flag.String("privacy", "unlisted", "Video privacy status")
)

func main() {
	flag.Parse()

	if *filename == "" {
		log.Fatalf("You must provide a filename of a video file to upload")
	}

	client := getClient(youtube.YoutubeUploadScope)

	service, err := youtube.New(client)
	if err != nil {
		log.Fatalf("Error creating YouTube client: %v", err)
	}

	upload := &youtube.Video{
		Snippet: &youtube.VideoSnippet{
			Title:       *title,
			Description: *description,
			CategoryId:  *category,
		},
		Status: &youtube.VideoStatus{PrivacyStatus: *privacy},
	}

	// The API returns a 400 Bad Request response if tags is an empty string.
	if strings.Trim(*keywords, "") != "" {
		upload.Snippet.Tags = strings.Split(*keywords, ",")
	}

	call := service.Videos.Insert("snippet,status", upload)

	file, err := os.Open(*filename)
	defer file.Close()
	if err != nil {
		log.Fatalf("Error opening %v: %v", *filename, err)
	}

	response, err := call.Media(file).Do()
	handleError(err, "")
	fmt.Printf("Upload successful! Video ID: %v\n", response.Id)
}

.NET

以下代码示例调用 API 的 videos.insert 方法,将视频上传到与请求关联的频道。

此示例使用 .NET 客户端库。

using System;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;

namespace Google.Apis.YouTube.Samples
{
  /// <summary>
  /// YouTube Data API v3 sample: upload a video.
  /// Relies on the Google APIs Client Library for .NET, v1.7.0 or higher.
  /// See https://developers.google.com/api-client-library/dotnet/get_started
  /// </summary>
  internal class UploadVideo
  {
    [STAThread]
    static void Main(string[] args)
    {
      Console.WriteLine("YouTube Data API: Upload Video");
      Console.WriteLine("==============================");

      try
      {
        new UploadVideo().Run().Wait();
      }
      catch (AggregateException ex)
      {
        foreach (var e in ex.InnerExceptions)
        {
          Console.WriteLine("Error: " + e.Message);
        }
      }

      Console.WriteLine("Press any key to continue...");
      Console.ReadKey();
    }

    private async Task Run()
    {
      UserCredential credential;
      using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
      {
        credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            // This OAuth 2.0 access scope allows an application to upload files to the
            // authenticated user's YouTube channel, but doesn't allow other types of access.
            new[] { YouTubeService.Scope.YoutubeUpload },
            "user",
            CancellationToken.None
        );
      }

      var youtubeService = new YouTubeService(new BaseClientService.Initializer()
      {
        HttpClientInitializer = credential,
        ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
      });

      var video = new Video();
      video.Snippet = new VideoSnippet();
      video.Snippet.Title = "Default Video Title";
      video.Snippet.Description = "Default Video Description";
      video.Snippet.Tags = new string[] { "tag1", "tag2" };
      video.Snippet.CategoryId = "22"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
      video.Status = new VideoStatus();
      video.Status.PrivacyStatus = "unlisted"; // or "private" or "public"
      var filePath = @"REPLACE_ME.mp4"; // Replace with path to actual movie file.

      using (var fileStream = new FileStream(filePath, FileMode.Open))
      {
        var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
        videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
        videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;

        await videosInsertRequest.UploadAsync();
      }
    }

    void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
    {
      switch (progress.Status)
      {
        case UploadStatus.Uploading:
          Console.WriteLine("{0} bytes sent.", progress.BytesSent);
          break;

        case UploadStatus.Failed:
          Console.WriteLine("An error prevented the upload from completing.\n{0}", progress.Exception);
          break;
      }
    }

    void videosInsertRequest_ResponseReceived(Video video)
    {
      Console.WriteLine("Video id '{0}' was successfully uploaded.", video.Id);
    }
  }
}

Ruby

此示例调用 API 的 videos.insert 方法,将视频上传到与请求关联的频道。

此示例使用 Ruby 客户端库。

#!/usr/bin/ruby

require 'rubygems'
gem 'google-api-client', '>0.7'
require 'google/api_client'
require 'google/api_client/client_secrets'
require 'google/api_client/auth/file_storage'
require 'google/api_client/auth/installed_app'
require 'trollop'

# A limited OAuth 2 access scope that allows for uploading files, but not other
# types of account access.
YOUTUBE_UPLOAD_SCOPE = 'https://www.googleapis.com/auth/youtube.upload'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'

def get_authenticated_service
  client = Google::APIClient.new(
    :application_name => $PROGRAM_NAME,
    :application_version => '1.0.0'
  )
  youtube = client.discovered_api(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION)

  file_storage = Google::APIClient::FileStorage.new("#{$PROGRAM_NAME}-oauth2.json")
  if file_storage.authorization.nil?
    client_secrets = Google::APIClient::ClientSecrets.load
    flow = Google::APIClient::InstalledAppFlow.new(
      :client_id => client_secrets.client_id,
      :client_secret => client_secrets.client_secret,
      :scope => [YOUTUBE_UPLOAD_SCOPE]
    )
    client.authorization = flow.authorize(file_storage)
  else
    client.authorization = file_storage.authorization
  end

  return client, youtube
end

def main
  opts = Trollop::options do
    opt :file, 'Video file to upload', :type => String
    opt :title, 'Video title', :default => 'Test Title', :type => String
    opt :description, 'Video description',
          :default => 'Test Description', :type => String
    opt :category_id, 'Numeric video category. See https://developers.google.com/youtube/v3/docs/videoCategories/list',
          :default => 22, :type => :int
    opt :keywords, 'Video keywords, comma-separated',
          :default => '', :type => String
    opt :privacy_status, 'Video privacy status: public, private, or unlisted',
          :default => 'public', :type => String
  end

  if opts[:file].nil? or not File.file?(opts[:file])
    Trollop::die :file, 'does not exist'
  end

  client, youtube = get_authenticated_service

  begin
    body = {
      :snippet => {
        :title => opts[:title],
        :description => opts[:description],
        :tags => opts[:keywords].split(','),
        :categoryId => opts[:category_id],
      },
      :status => {
        :privacyStatus => opts[:privacy_status]
      }
    }

    videos_insert_response = client.execute!(
      :api_method => youtube.videos.insert,
      :body_object => body,
      :media => Google::APIClient::UploadIO.new(opts[:file], 'video/*'),
      :parameters => {
        :uploadType => 'resumable',
        :part => body.keys.join(',')
      }
    )

    videos_insert_response.resumable_upload.send_all(client)

    puts "Video id '#{videos_insert_response.data.id}' was successfully uploaded."
  rescue Google::APIClient::TransmissionError => e
    puts e.result.body
  end
end

main

错误

下表列出了 API 在响应对此方法的调用时可能会返回的出错提示。如需了解详情,请参阅错误消息文档。

错误类型 错误详情 说明
badRequest (400) defaultLanguageNotSet 请求尝试添加本地化视频详情,但未指定视频详情的默认语言。
badRequest (400) invalidCategoryId snippet.categoryId 属性指定了无效的类别 ID。请使用 videoCategories.list 方法检索受支持的类别。
badRequest (400) invalidDescription 请求元数据指定了无效的视频说明。
badRequest (400) invalidFilename Slug 标头中指定的视频文件名无效。
badRequest (400) invalidPublishAt 请求元数据指定了无效的计划发布时间。
badRequest (400) invalidRecordingDetails 请求元数据中的 recordingDetails 对象指定了无效的录制详情。
badRequest (400) invalidTags 请求元数据指定了无效的视频关键字。
badRequest (400) invalidTitle 请求元数据指定了无效或空白的视频标题。
badRequest (400) invalidVideoGameRating 请求元数据指定了无效的电子游戏评级。
badRequest (400) invalidVideoMetadata 请求元数据无效。
badRequest (400) mediaBodyRequired 请求不包含视频内容。
badRequest (400) uploadLimitExceeded 用户上传的视频数量已超出上限。
forbidden (403) forbidden
forbidden (403) forbiddenLicenseSetting 请求尝试为视频设置无效的许可。
forbidden (403) forbiddenPrivacySetting 请求尝试为视频设置无效的隐私设置。

试试看!

使用 APIs Explorer 调用此 API,查看 API 请求和响应。