將影片上傳至 YouTube,並視需要設定影片的中繼資料。
這個方法支援媒體上傳。上傳的檔案必須符合下列限制:
- 檔案大小上限:256 GB
- 接受的媒體 MIME 類型:
video/*、application/octet-stream
配額影響:每天 100 次通話。呼叫這個方法時,系統會從影片上傳配額 bucket 中扣除 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 |
stringpart 參數在這項作業中有兩個用途。它會識別寫入作業將設定的屬性,以及 API 回應將包含的屬性。請注意,並非所有部分都包含可在插入或更新影片時設定的屬性。舉例來說, statistics 物件會封裝 YouTube 為影片計算的統計資料,且不含可設定或修改的值。如果參數值指定的 part 不含可變動值,該 part 仍會包含在 API 回應中。下列清單包含可納入參數值的 part 名稱:
|
|
| 選用參數 | ||
notifySubscribers |
booleannotifySubscribers 參數會指出 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.titlesnippet.descriptionsnippet.tags[]snippet.categoryIdsnippet.defaultLanguagelocalizations.(key)localizations.(key).titlelocalizations.(key).descriptionstatus.embeddablestatus.licensestatus.privacyStatus:如未指定這項屬性的值,上傳影片的隱私權狀態預設為public。根據創作者帳戶設定,某些上傳內容可能會預設為private,詳情請參閱 YouTube 說明中心。透過未經驗證 API 專案上傳的影片,不會限制為私人觀看模式。status.publicStatsViewablestatus.publishAtstatus.selfDeclaredMadeForKidsstatus.containsSyntheticMediarecordingDetails.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); } } }
小茹
這個範例會呼叫 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 要求和回應。