Videos: insert

凡是在 2020 年 7 月 28 日後建立且未經驗證的 API 專案,透過 videos.insert 端點上傳的影片都將無法使用私人觀看模式。如要解除這項限制,每個 API 專案都必須接受稽核,以確認是否遵守服務條款。詳情請參閱 API 修訂版本記錄

將影片上傳至 YouTube,並視需要設定影片的中繼資料。

這個方法支援媒體上傳功能。上傳的檔案必須符合下列限制:

  • 檔案大小上限:256 GB
  • 接受的媒體 MIME 類型: video/*application/octet-stream

配額影響:呼叫這個方法時,配額費用為 1600 個單位。

常見用途

要求

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 名稱:
  • 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
    • status.publicStatsViewable
    • status.publishAt
    • status.selfDeclaredMadeForKids
    • status.containsSyntheticMedia
    • recordingDetails.recordingDate

回應

如果成功的話,這個方法會在回應內文中傳回 video 資源

範例

注意:下列程式碼範例可能不代表所有支援的程式語言。如需支援語言清單,請參閱用戶端程式庫說明文件。

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);
    }
  }
}

小茹

這個範例會呼叫 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 要求和回應。