YouTube API v3的记录非常糟糕。我已经多次报告了很多错误,但没有人做出反应。 我仍然需要使用此API上传缩略图。 该指南指出:
POST https://www.googleapis.com/youtube/v3/thumbnails/set
Auth范围:
- https://www.googleapis.com/auth/youtubepartner
- https://www.googleapis.com/auth/youtube.upload
- https://www.googleapis.com/auth/youtube
参数:
- videoId:string videoId参数指定要为其提供自定义视频缩略图的YouTube视频ID。
首先 - 网址错误。它必须是https://www.googleapis.com/upload/youtube/v3/thumbnails/set
。
现在关注代码,它使用Unirest
:
final HttpResponse<String> response = Unirest.post("https://www.googleapis.com/upload/youtube/v3/thumbnails/set")
.header("Content-Type", "application/octet-stream")
.header("Authorization", accountService.getAuthentication(account).getHeader())
.field("videoId", videoid)
.field("thumbnail", thumbnail)
.asString();
收到回复:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Required parameter: videoId",
"locationType": "parameter",
"location": "videoId"
}
],
"code": 400,
"message": "Required parameter: videoId"
}
}
这怎么可能? videoId已设置好! 有人已经玩过这部分API吗?
我可以将请求更改为
Unirest.post("https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=" + videoid)
.header("Content-Type", "application/octet-stream")
.header("Authorization", accountService.getAuthentication(account).getHeader())
.field("mediaUpload", thumbnail)
.asString();
这会给我带来这个错误:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "backendError",
"message": "Backend Error"
}
],
"code": 503,
"message": "Backend Error"
}
}
编辑: 与Ibrahim Ulukaya发布的URL相同的请求(参考指南中的原始URL):
{
"error": {
"errors": [
{
"domain": "global",
"reason": "wrongUrlForUpload",
"message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/thumbnails/set"
}
],
"code": 400,
"message": "Uploads must be sent to the upload URL. Re-send this request to https://www.googleapis.com/upload/youtube/v3/thumbnails/set"
}
}
答案 0 :(得分:3)
我们挖掘了这个问题,如果您不想使用该库,可以采取以下步骤。
1)发布https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=VIDEO_ID&uploadType=resumable 身体空虚
2)获取响应的Location:标题中的URL,并使用Content-Type:image / png和正文中的缩略图POST到该URL
答案 1 :(得分:1)
网址将被修复。
您还需要在频道中拥有特定权限才能设置自定义缩略图。
这是Java,我刚刚编写并测试过,它可以工作。
/*
* Copyright (c) 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.api.services.samples.youtube.cmdline.youtube_cmdline_uploadthumbnail_sample;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.java6.auth.oauth2.FileCredentialStore;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.googleapis.media.MediaHttpUploader;
import com.google.api.client.googleapis.media.MediaHttpUploaderProgressListener;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.InputStreamContent;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.YouTube.Thumbnails.Set;
import com.google.api.services.youtube.model.ThumbnailSetResponse;
import com.google.common.collect.Lists;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
/**
* This sample uploads and sets a custom thumbnail for a video by:
*
* 1. Uploading a image utilizing "MediaHttpUploader" 2. Setting the uploaded image as a custom
* thumbnail to the video via "youtube.thumbnails.set" method
*
* @author Ibrahim Ulukaya
*/
public class UploadThumbnail {
/**
* Global instance of the HTTP transport.
*/
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/**
* Global instance of the JSON factory.
*/
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
/**
* Global instance of Youtube object to make all API requests.
*/
private static YouTube youtube;
/* Global instance of the format used for the image being uploaded (MIME type). */
private static String IMAGE_FILE_FORMAT = "image/png";
/**
* Authorizes the installed application to access user's protected data.
*
* @param scopes list of scopes needed to run youtube upload.
*/
private static Credential authorize(List<String> scopes) throws IOException {
// Load client secrets.
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY,
new InputStreamReader(UploadThumbnail.class.getResourceAsStream("/client_secrets.json")));
// Checks that the defaults have been replaced (Default = "Enter X here").
if (clientSecrets.getDetails().getClientId().startsWith("Enter")
|| clientSecrets.getDetails().getClientSecret().startsWith("Enter ")) {
System.out.println(
"Enter Client ID and Secret from https://code.google.com/apis/console/?api=youtube"
+ "into youtube-cmdline-uploadthumbnail-sample/src/main/resources/client_secrets.json");
System.exit(1);
}
// Set up file credential store.
FileCredentialStore credentialStore = new FileCredentialStore(
new File(System.getProperty("user.home"), ".credentials/youtube-api-uploadthumbnail.json"),
JSON_FACTORY);
// Set up authorization code flow.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, scopes).setCredentialStore(credentialStore)
.build();
// Build the local server and bind it to port 8080
LocalServerReceiver localReceiver = new LocalServerReceiver.Builder().setPort(8080).build();
// Authorize.
return new AuthorizationCodeInstalledApp(flow, localReceiver).authorize("user");
}
/**
* This is a very simple code sample that looks up a user's channel, then features the most
* recently uploaded video in the bottom left hand corner of every single video in the channel.
*
* @param args command line args (not used).
*/
public static void main(String[] args) {
// An OAuth 2 access scope that allows for full read/write access.
List<String> scopes = Lists.newArrayList("https://www.googleapis.com/auth/youtube");
try {
// Authorization.
Credential credential = authorize(scopes);
// YouTube object used to make all API requests.
youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(
"youtube-cmdline-addfeaturedvideo-sample").build();
// Get the user selected video Id.
String videoId = getVideoIdFromUser();
System.out.println("You chose " + videoId + " to upload a thumbnail.");
// Get the user selected local image file to upload.
File imageFile = getImageFromUser();
System.out.println("You chose " + imageFile + " to upload.");
InputStreamContent mediaContent = new InputStreamContent(
IMAGE_FILE_FORMAT, new BufferedInputStream(new FileInputStream(imageFile)));
mediaContent.setLength(imageFile.length());
// Create a request to set the selected mediaContent as the thumbnail of the selected video.
Set thumbnailSet = youtube.thumbnails().set(videoId, mediaContent);
// Set the upload type and add event listener.
MediaHttpUploader uploader = thumbnailSet.getMediaHttpUploader();
/*
* Sets whether direct media upload is enabled or disabled. True = whole media content is
* uploaded in a single request. False (default) = resumable media upload protocol to upload
* in data chunks.
*/
uploader.setDirectUploadEnabled(false);
MediaHttpUploaderProgressListener progressListener = new MediaHttpUploaderProgressListener() {
@Override
public void progressChanged(MediaHttpUploader uploader) throws IOException {
switch (uploader.getUploadState()) {
case INITIATION_STARTED:
System.out.println("Initiation Started");
break;
case INITIATION_COMPLETE:
System.out.println("Initiation Completed");
break;
case MEDIA_IN_PROGRESS:
System.out.println("Upload in progress");
System.out.println("Upload percentage: " + uploader.getProgress());
break;
case MEDIA_COMPLETE:
System.out.println("Upload Completed!");
break;
case NOT_STARTED:
System.out.println("Upload Not Started!");
break;
}
}
};
uploader.setProgressListener(progressListener);
// Execute upload and set thumbnail.
ThumbnailSetResponse setResponse = thumbnailSet.execute();
// Print out returned results.
System.out.println("\n================== Uploaded Thumbnail ==================\n");
System.out.println(" - Url: " + setResponse.getItems().get(0).getDefault().getUrl());
} catch (GoogleJsonResponseException e) {
System.err.println("GoogleJsonResponseException code: " + e.getDetails().getCode() + " : "
+ e.getDetails().getMessage());
e.printStackTrace();
} catch (IOException e) {
System.err.println("IOException: " + e.getMessage());
e.printStackTrace();
}
}
/*
* Prompts for a video ID from standard input and returns it.
*/
private static String getVideoIdFromUser() throws IOException {
String title = "";
System.out.print("Please enter a video Id to update: ");
BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
title = bReader.readLine();
if (title.length() < 1) {
// If nothing is entered, exits
System.out.print("Video Id can't be empty!");
System.exit(1);
}
return title;
}
/*
* Prompts for the path of the image file to upload from standard input and returns it.
*/
private static File getImageFromUser() throws IOException {
String path = "";
System.out.print("Please enter the path of the image file to upload: ");
BufferedReader bReader = new BufferedReader(new InputStreamReader(System.in));
path = bReader.readLine();
if (path.length() < 1) {
// If nothing is entered, exits
System.out.print("Path can not be empty!");
System.exit(1);
}
return new File(path);
}
}
答案 2 :(得分:0)
给出的答案甚至不是正确的!如果您在此网址中发布了没有图片的网址:
https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId=VIDEO_ID&uploadType=resumable
您将收到此错误:
&#34; 400:mediaBodyRequired&#34;
此错误在本页底部的YouTube文档中有所描述:
https://developers.google.com/youtube/v3/docs/thumbnails/set
为:
&#34;请求不包含图像内容。&#34;
虽然他们的文档留下了很多东西(想想categoryId),但他们已经死了,因为我刚刚尝试了Ibrahim发布的第一个解决方案并收到了错误。虽然他表示不提供身体中的图像数据,但文档和我自己的研究显示正好相反。
解决方案是发布包含图像主体的URL。这样做时,我收到了这个回复:
{&#34; kind&#34;:&#34; youtube#thumbnailSetResponse&#34;,&#34; etag&#34;:&#34; \&#34; kYnGHzMaBhcGeLrcKRx6PAIUosY / lcDPfygjJkG-yyzdBp0dKhY2xMY \&# 34;&#34;,&#34;项目&#34;:[{&#34;默认&#34;:{&#34; url&#34;:&#34; // i.ytimg.com/vi /fyBx3v1gmbM/default.jpg" ;,&#34; width&#34;:120,&#34; height&#34;:90},&#34; medium&#34;:{&#34; url&#34 ;:&#34; // i.ytimg.com/vi/fyBx3v1gmbM/mqdefault.jpg" ;,&#34; width&#34;:320,&#34; height&#34;:180},&# 34;高&#34;:{&#34; url&#34;:&#34; // i.ytimg.com/vi/fyBx3v1gmbM/hqdefault.jpg" ;,&#34; width&#34;:480 ,&#34;身高&#34;:360},&#34;标准&#34;:{&#34; url&#34;:&#34; // i.ytimg.com/vi/fyBx3v1gmbM/sddefault。 jpg&#34;,&#34; width&#34;:640,&#34; height&#34;:480},&#34; maxres&#34;:{&#34; url&#34;:&#34 ; // i.ytimg.com/vi/fyBx3v1gmbM/maxresdefault.jpg" ;,&#34; width&#34;:1280,&#34; height&#34;:720}}]}
不幸的是,它并没有真正改变缩略图,但我认为这是他们的API服务器和他们的缩略图处理排队的问题。它确实会返回一个成功的响应。不知道为什么缩略图不会改变。