使用 YouTube 数据 API (v3) 通过 API 键更新视频出现 401 错误
use YouTube Data API (v3) to update a video via API keys got a 401 error
在我的 java 后端应用程序中,我想每周使用 quartz 作业将我的 YouTube 视频状态从 public 更改为私有,这是一项预定的工作。所以我使用 YouTube 数据 API (v3) 的 Videos Update 来完成这项工作。
参见 YouTube
数据API
参考视频:更新 和代码示例Resource>videos,Method>update。
根据Obtaining authorization credentials,有两种获取授权凭据的方法,一种是OAuth 2.0,另一种是使用API Keys.我选择使用 API Keys 因为它比 oauth2.
更简单
我已经从 Google API 控制台检索了 API 密钥,我 运行 从 youtube 的文档 Resource>videos,Method>update 和 [=61] 复制了代码示例=] 他们,他们都得到了 401 错误。
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Login Required.",
"domain": "global",
"reason": "required",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED"
}
}
我不明白为什么我不能使用 API 键来调用 videos.update。我不想使用 OAuth2,我认为使用 API 密钥更好 way.Because,无法打开浏览器 window 并让用户在quartz 工作,谁能告诉我问题是什么以及如何解决?
代码示例如下
Java 基于
/**
* Sample Java code for youtube.videos.update
* See instructions for running these code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#java
*/
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
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.model.Video;
import com.google.api.services.youtube.model.VideoLocalization;
import com.google.api.services.youtube.model.VideoSnippet;
import com.google.api.services.youtube.model.VideoStatus;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
public class ApiExample {
// You need to set this value for your code to compile.
// For example: ... DEVELOPER_KEY = "YOUR ACTUAL KEY";
private static final String DEVELOPER_KEY = "...";
private static final String APPLICATION_NAME = "API code samples";
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
/**
* Build and return an authorized API client service.
*
* @return an authorized API client service
* @throws GeneralSecurityException, IOException
*/
public static YouTube getService() throws GeneralSecurityException, IOException {
final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
return new YouTube.Builder(httpTransport, JSON_FACTORY, null)
.setApplicationName(APPLICATION_NAME)
.build();
}
/**
* Call function to create API service object. Define and
* execute API request. Print API response.
*
* @throws GeneralSecurityException, IOException, GoogleJsonResponseException
*/
public static void main(String[] args)
throws GeneralSecurityException, IOException, GoogleJsonResponseException {
YouTube youtubeService = getService();
// Define the Video object, which will be uploaded as the request body.
Video video = new Video();
// Add the id string property to the Video object.
video.setId("9BByHcBGMP4");
// Add the localizations object property to the Video object.
HashMap<String, VideoLocalization> localizations = new HashMap<>();
VideoLocalization esLocalization = new VideoLocalization();
esLocalization.setDescription("Esta descripcion es en español.");
esLocalization.setTitle("no hay nada a ver aqui");
localizations.put("es", esLocalization);
video.setLocalizations(localizations);
// Add the snippet object property to the Video object.
VideoSnippet snippet = new VideoSnippet();
snippet.setCategoryId("22");
snippet.setDefaultLanguage("en");
snippet.setDescription("This description is in English.");
String[] tags = {
"new tags",
};
snippet.setTags(Arrays.asList(tags));
snippet.setTitle("There is nothing to see here.");
video.setSnippet(snippet);
// Add the status object property to the Video object.
VideoStatus status = new VideoStatus();
status.setPrivacyStatus("private");
video.setStatus(status);
// Define and execute the API request
YouTube.Videos.Update request = youtubeService.videos()
.update("snippet,status,localizations", video);
Video response = request.setKey(DEVELOPER_KEY).execute();
System.out.println(response);
}
}
Java基于脚本
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
</head>
<body>
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for youtube.videos.update
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#javascript
*/
function loadClient() {
gapi.client.setApiKey("...");
return gapi.client.load("https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded before calling this method.
function execute() {
return gapi.client.youtube.videos.update({
"part": [
"snippet,status,localizations"
],
"resource": {
"id": "9BByHcBGMP4",
"snippet": {
"categoryId": "22",
"defaultLanguage": "en",
"description": "This description is in English.",
"tags": [
"new tags"
],
"title": "There is nothing to see here."
},
"status": {
"privacyStatus": "private"
},
"localizations": {
"es": {
"title": "no hay nada a ver aqui",
"description": "Esta descripcion es en español."
}
}
}
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client");
</script>
<button onclick="loadClient()">load</button>
<button onclick="execute()">execute</button>
</body>
</html>
根据您自己引用的 the official doc,要调用 Videos.update
API 端点,您需要获得适当的授权:
This request requires authorization with at least one of the following scopes (read more about authentication and authorization).
Scope
https://www.googleapis.com/auth/youtubepartner
https://www.googleapis.com/auth/youtube
https://www.googleapis.com/auth/youtube.force-ssl
因此,您无法避免在您的应用程序中使用 OAuth 2.0 authentication/authorization 流程。请注意,API 键用于 只读 public 数据。
对于您问题中的部分:
[...] it is impossible to open a browser window and make the user to do a oauth login and authorization in a quartz job [...]
API 有解决方案。请阅读以下两个文档:OAuth 2.0 for Mobile & Desktop Apps and Using OAuth 2.0 for Web Server Applications.
我最近针对类似问题给出了关于您必须执行的操作的简要、顶级描述。该答案可能会帮助您更轻松地理解解决问题的方法。
在我的 java 后端应用程序中,我想每周使用 quartz 作业将我的 YouTube 视频状态从 public 更改为私有,这是一项预定的工作。所以我使用 YouTube 数据 API (v3) 的 Videos Update 来完成这项工作。
参见 YouTube 数据API 参考视频:更新 和代码示例Resource>videos,Method>update。 根据Obtaining authorization credentials,有两种获取授权凭据的方法,一种是OAuth 2.0,另一种是使用API Keys.我选择使用 API Keys 因为它比 oauth2.
更简单我已经从 Google API 控制台检索了 API 密钥,我 运行 从 youtube 的文档 Resource>videos,Method>update 和 [=61] 复制了代码示例=] 他们,他们都得到了 401 错误。
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
{
"message": "Login Required.",
"domain": "global",
"reason": "required",
"location": "Authorization",
"locationType": "header"
}
],
"status": "UNAUTHENTICATED"
}
}
我不明白为什么我不能使用 API 键来调用 videos.update。我不想使用 OAuth2,我认为使用 API 密钥更好 way.Because,无法打开浏览器 window 并让用户在quartz 工作,谁能告诉我问题是什么以及如何解决?
代码示例如下
Java 基于
/**
* Sample Java code for youtube.videos.update
* See instructions for running these code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#java
*/
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
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.model.Video;
import com.google.api.services.youtube.model.VideoLocalization;
import com.google.api.services.youtube.model.VideoSnippet;
import com.google.api.services.youtube.model.VideoStatus;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
public class ApiExample {
// You need to set this value for your code to compile.
// For example: ... DEVELOPER_KEY = "YOUR ACTUAL KEY";
private static final String DEVELOPER_KEY = "...";
private static final String APPLICATION_NAME = "API code samples";
private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
/**
* Build and return an authorized API client service.
*
* @return an authorized API client service
* @throws GeneralSecurityException, IOException
*/
public static YouTube getService() throws GeneralSecurityException, IOException {
final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
return new YouTube.Builder(httpTransport, JSON_FACTORY, null)
.setApplicationName(APPLICATION_NAME)
.build();
}
/**
* Call function to create API service object. Define and
* execute API request. Print API response.
*
* @throws GeneralSecurityException, IOException, GoogleJsonResponseException
*/
public static void main(String[] args)
throws GeneralSecurityException, IOException, GoogleJsonResponseException {
YouTube youtubeService = getService();
// Define the Video object, which will be uploaded as the request body.
Video video = new Video();
// Add the id string property to the Video object.
video.setId("9BByHcBGMP4");
// Add the localizations object property to the Video object.
HashMap<String, VideoLocalization> localizations = new HashMap<>();
VideoLocalization esLocalization = new VideoLocalization();
esLocalization.setDescription("Esta descripcion es en español.");
esLocalization.setTitle("no hay nada a ver aqui");
localizations.put("es", esLocalization);
video.setLocalizations(localizations);
// Add the snippet object property to the Video object.
VideoSnippet snippet = new VideoSnippet();
snippet.setCategoryId("22");
snippet.setDefaultLanguage("en");
snippet.setDescription("This description is in English.");
String[] tags = {
"new tags",
};
snippet.setTags(Arrays.asList(tags));
snippet.setTitle("There is nothing to see here.");
video.setSnippet(snippet);
// Add the status object property to the Video object.
VideoStatus status = new VideoStatus();
status.setPrivacyStatus("private");
video.setStatus(status);
// Define and execute the API request
YouTube.Videos.Update request = youtubeService.videos()
.update("snippet,status,localizations", video);
Video response = request.setKey(DEVELOPER_KEY).execute();
System.out.println(response);
}
}
Java基于脚本
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
</head>
<body>
<script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for youtube.videos.update
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/guides/code_samples#javascript
*/
function loadClient() {
gapi.client.setApiKey("...");
return gapi.client.load("https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded before calling this method.
function execute() {
return gapi.client.youtube.videos.update({
"part": [
"snippet,status,localizations"
],
"resource": {
"id": "9BByHcBGMP4",
"snippet": {
"categoryId": "22",
"defaultLanguage": "en",
"description": "This description is in English.",
"tags": [
"new tags"
],
"title": "There is nothing to see here."
},
"status": {
"privacyStatus": "private"
},
"localizations": {
"es": {
"title": "no hay nada a ver aqui",
"description": "Esta descripcion es en español."
}
}
}
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client");
</script>
<button onclick="loadClient()">load</button>
<button onclick="execute()">execute</button>
</body>
</html>
根据您自己引用的 the official doc,要调用 Videos.update
API 端点,您需要获得适当的授权:
This request requires authorization with at least one of the following scopes (read more about authentication and authorization).
Scope
https://www.googleapis.com/auth/youtubepartner
https://www.googleapis.com/auth/youtube
https://www.googleapis.com/auth/youtube.force-ssl
因此,您无法避免在您的应用程序中使用 OAuth 2.0 authentication/authorization 流程。请注意,API 键用于 只读 public 数据。
对于您问题中的部分:
[...] it is impossible to open a browser window and make the user to do a oauth login and authorization in a quartz job [...]
API 有解决方案。请阅读以下两个文档:OAuth 2.0 for Mobile & Desktop Apps and Using OAuth 2.0 for Web Server Applications.