背景描述
前段时间公司要求对接海外YouTube平台实现视频上传的功能,由于海外文档描述不详细,且本人英语功底不好,过程中踩了很多坑,写出这篇文章出来希望能帮助到有需要的人。
对接YouTube平台的准备
开发环境:idea 、jdk1.8、maven
开发准备:
- 需要一个Google账号
- 需要登录到Google控制台创建应用开启YouTube平台Api
- 需要需要去Google控制台下载client_secrets.json文件
下面是图文教程:
-
Google控制台 创建应用
1.1 选择应用类型
1.2 client_secrets.json文件
2.开启YouTube的Api
2.1 启用此api
环境准备好后咱们先了解一下接入流程
接入流程
调用YouTube Api需要用到Google OAuth2.0 授权,授权完成之后Google会返回给你一个访问令牌,在令牌有效期内可以访问Google Api 而 YouTube Api就是Google Api 下的一种。
下面来看下Google OAuth2.0的授权流程:
- 应用向Google oaAuth2服务器发起对用户对该应用的授权请求,利用Google Api返回给应用一个用于用户给应用授权的链接
- 用户在浏览器打开授权链接后选择授权给应用的权限后点击确定,Google oaAuth2会回调该应用配置在谷歌后台的回调地址
- Google oaAuth服务器回调应用接口会返回用户授权码(code)以及用户给应用赋予的权限(scope),应用拿到用户授权码之后向GoogleoaAuth服务器发起请求把用户授权码兑换成令牌
- 拿到oaAuth服务器返回的令牌之后就能够访问YouTube的API了,这里要注意Google oaAuth2服务器返回的令牌是有时间限制的在谷歌后台可以设置过期时间,当令牌过期后需要拿着Google oaAuth2令牌里面的refresh_token向Google oaAuth2服务器重新申请令牌
了解完流程之后咱们可以正式进入开发了
代码开发
- maven坐标
<!-- maven 坐标 -->
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-youtube</artifactId>
<version>v3-rev222-1.25.0</version>
</dependency>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client-gson</artifactId>
<version>2.0.0</version>
</dependency>
- 配置类
// 基础配置
@Configuration
public class YoutubeConfig {
// 这个是client_secrets.json的文件路径,这是自己写的demo,只要能加载就行
private static String clientSecretsPath = "E:\\Java_source_code\\youtube-video\\youtube-admin\\src\\main\\resources\\config\\client_secrets.json";
// 调用YouTubeApi所需权限列表,具体哪个url对应那个权限请翻阅YouTube官方文档
private static List<String> roleList = Arrays.asList(
"https://www.googleapis.com/auth/youtube",
"https://www.googleapis.com/auth/youtube.channel-memberships.creator",
"https://www.googleapis.com/auth/youtube.force-ssl",
"https://www.googleapis.com/auth/youtube.readonly",
"https://www.googleapis.com/auth/youtube.upload",
"https://www.googleapis.com/auth/youtubepartner",
"https://www.googleapis.com/auth/youtubepartner-channel-audit",
"https://www.googleapis.com/auth/youtubepartner-content-owner-readonly"
);
@Bean
public HttpTransport getHttpTransport() throws GeneralSecurityException, IOException {
return GoogleNetHttpTransport.newTrustedTransport();
}
@Bean
public JsonFactory getJsonFactory() {
return GsonFactory.getDefaultInstance();
}
@Bean
public GoogleClientSecrets getGoogleClientSecrets(JsonFactory jsonFactory) throws IOException {
InputStream stream = new FileInputStream(new File(clientSecretsPath));
return GoogleClientSecrets.load(jsonFactory, new InputStreamReader(stream));
}
@Bean
public GoogleAuthorizationCodeFlow getGoogleAuthorizationCodeFlow(HttpTransport httpTransport,
JsonFactory jsonFactory,
GoogleClientSecrets clientSecrets) {
return new GoogleAuthorizationCodeFlow.Builder(
httpTransport, jsonFactory, clientSecrets,
roleList)
.build();
}
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
- 获取Google授权
@Controller
@RequestMapping(value = "/youtube")
public class YoutubeAuthController {
@Value("${youtube.redirect-uri}")
private String redirectUri;
@Autowired
private GoogleAuthorizationCodeFlow flow;
@Autowired
private GoogleClientSecrets clientSecrets;
private static GoogleTokenResponse googleTokenResponse;
private static String DOT = ",";
public static ConcurrentHashMap<String,Credential> CREDENTIAL_MAP = new ConcurrentHashMap<>();
/**
* Google回调接口, 只有用户第一次授权时会返回refreshToken, 这里status作为requestId使用
* @param code
* @param scope
* @param state
* @return
* @throws Exception
*/
@RequestMapping(value = "/callback")
@ResponseBody
public String getYoutubeCallback(String code, String scope,String state) throws Exception {
List<NameValuePair> parameters = new ArrayList<>();
parameters.add(new BasicNameValuePair("code", code));
parameters.add(new BasicNameValuePair("client_id", clientSecrets.getWeb().getClientId()));
parameters.add(new BasicNameValuePair("client_secret", clientSecrets.getWeb().getClientSecret()));
parameters.add(new BasicNameValuePair("grant_type", "authorization_code"));
parameters.add(new BasicNameValuePair("redirect_uri",redirectUri));
UrlEncodedFormEntity encodedFormEntity = new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8.name());
String url = "https://oauth2.googleapis.com/token";
HttpPost request = new HttpPost();
request.setEntity(encodedFormEntity);
String response = HttpClientUtil.doPost(url, encodedFormEntity);
System.out.println(response);
TokenResponse tokenResponse = JSON.parseObject(response,TokenResponse.class);
Credential credential = flow.createAndStoreCredential(tokenResponse, state);
CREDENTIAL_MAP.put(state,credential);
return "ok";
}
private String getRoleString(String roles) {
if (roles.contains(DOT) && roles.endsWith(DOT)) {
return roles.substring(0,roles.length() - 1);
} else {
return roles;
}
}
/**
* Google刷新令牌接口
* @return
*/
@RequestMapping(value = "/refreshToken")
@ResponseBody
public String refreshToken(String uid) throws Exception {
Credential credential = CREDENTIAL_MAP.get(uid);
List<NameValuePair> parameters = new ArrayList<>();
parameters.add(new BasicNameValuePair("client_id", clientSecrets.getWeb().getClientId()));
parameters.add(new BasicNameValuePair("client_secret", clientSecrets.getWeb().getClientSecret()));
parameters.add(new BasicNameValuePair("grant_type", "refresh_token"));
parameters.add(new BasicNameValuePair("refresh_token",credential.getRefreshToken()));
UrlEncodedFormEntity encodedFormEntity = new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8.name());
String url = "https://oauth2.googleapis.com/token";
HttpPost request = new HttpPost();
request.setEntity(encodedFormEntity);
return HttpClientUtil.doPost(url, encodedFormEntity);
}
/**
* 获取用户授权url接口
* @param uid
* @return
*/
@GetMapping(value = "/applyRole")
@ResponseBody
public String toApplyRole(String uid) {
try {
return flow.newAuthorizationUrl()
.setRedirectUri(redirectUri)
.setAccessType("offline")
// 这个值可以不设置,授权成功后Google会返回这个值给你
.setState(uid)
// 这个值是指定账号的,不用指定账号不用设置
.set("login_hint",uid)
.build();
} catch (Exception e) {
e.printStackTrace();
return "the request happen a error in runtime";
}
}
/**
* Google撤销令牌接口
* @return
*/
@RequestMapping(value = "/revoke")
@ResponseBody
public String revokeToken(String refresh_token) throws Exception {
Credential credential = CREDENTIAL_MAP.get(uid);
String url1 = "https://oauth2.googleapis.com/revoke?token=" + refresh_token;
// String url2 = "https://oauth2.googleapis.com/revoke?token="+"1//0evHFaeshE0tACgYIARAAGA4SNwF-L9IrQoRaXWvYVLqgGk8jOl_KWlobz8q_uqk36vuwWD6MVHKoBHr-7n7e5aLNXP0AYYh5xQ0";
return HttpClientUtil.doPost(url1, null);
}
}
记住:同一个账号只能给一个应用授权一次,同一个账号再次授权会报错,这段代码先理解一下,了解一下我这是啥意思,再动手写自己的代码,不要盲目copy !!!
拿到访问令牌之后就能对YouYube的api进行访问了
下面试操作YouTube视频接口的代码
@Controller
@RequestMapping(value = "/api")
public class YouTubeApiController {
@Autowired
private JsonFactory jsonFactory;
@Autowired
private HttpTransport httpTransport;
@Autowired
private GoogleAuthorizationCodeFlow flow;
private static final String APP_NAME = "web-app-youtube";
@GetMapping(value = "/getChannel")
@ResponseBody
public ChannelListResponse getChannel(String uid) throws IOException {
Credential credential = YoutubeAuthController.CREDENTIAL_MAP.get(uid);
// 获取凭证
/* GoogleTokenResponse tokenResponse = JSON.parseObject("{\n" +
" \"access_token\": \"ya29.a0AX9GBdWDTl_WDHjAhMhqfHOv8Tee5o3Y8G-Un46rjLxVIXMBaUC8aUHzQWtwCzENq9EBPkN5WoXgiIgReOmBhEjIzJgZ3ZAbQt0em3m5NNFQe6LtL3Z0oj6UMHYHd0H4UJ2_N5Td1g3ggudW_539A09HtTV2aCgYKAdcSARASFQHUCsbCk4dDMR9R3-VivIgsglOayw0163\",\n" +
" \"expires_in\": 3599,\n" +
" \"refresh_token\": \"1//0eggCEbOSfmnnCgYIARAAGA4SNwF-L9IryVDE5t8GTDyOVAzPOPFc-TGJmiZOkUkzTVPLZuYMNOURZYA2fklO1_nhlSy3SOAsU4w\",\n" +
" \"scope\": \"https://www.googleapis.com/auth/youtubepartner https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtubepartner-channel-audit https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtubepartner-content-owner-readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube.channel-memberships.creator\",\n" +
" \"token_type\": \"Bearer\"\n" +
"}",GoogleTokenResponse.class);*/
//Credential credential = flow.createAndStoreCredential(tokenResponse.transfer(),null);
YouTube youtubeService = new YouTube.Builder(httpTransport, jsonFactory, credential).build();
String respParam = "brandingSettings,id,status";
YouTube.Channels.List request = youtubeService.channels().list(respParam);
ChannelListResponse response = request
.setMine(true)
.execute();
return response;
}
/**
* Google上传视频接口
* @return
*/
@RequestMapping(value = "/uploadVideo")
@ResponseBody
public Video uploadVideo(String uid, MultipartFile file) throws Exception {
/* // 获取凭证
GoogleTokenResponse tokenResponse = JSON.parseObject("{\n" +
" \"access_token\": \"ya29.a0AX9GBdWDTl_WDHjAhMhqfHOv8Tee5o3Y8G-Un46rjLxVIXMBaUC8aUHzQWtwCzENq9EBPkN5WoXgiIgReOmBhEjIzJgZ3ZAbQt0em3m5NNFQe6LtL3Z0oj6UMHYHd0H4UJ2_N5Td1g3ggudW_539A09HtTV2aCgYKAdcSARASFQHUCsbCk4dDMR9R3-VivIgsglOayw0163\",\n" +
" \"expires_in\": 3599,\n" +
" \"refresh_token\": \"1//0eggCEbOSfmnnCgYIARAAGA4SNwF-L9IryVDE5t8GTDyOVAzPOPFc-TGJmiZOkUkzTVPLZuYMNOURZYA2fklO1_nhlSy3SOAsU4w\",\n" +
" \"scope\": \"https://www.googleapis.com/auth/youtubepartner https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtubepartner-channel-audit https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtubepartner-content-owner-readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube.channel-memberships.creator\",\n" +
" \"token_type\": \"Bearer\"\n" +
"}",GoogleTokenResponse.class);
Credential credential = flow.createAndStoreCredential(tokenResponse.transfer(),uid);*/
Credential credential = YoutubeAuthController.CREDENTIAL_MAP.get(uid);
YouTube youtubeService = new YouTube.Builder(httpTransport, jsonFactory, credential).build();
Video uploadedVideo = new Video();
VideoStatus status = new VideoStatus();
status.setPrivacyStatus("public");
uploadedVideo.setStatus(status);
VideoSnippet snippet = new VideoSnippet();
snippet.setTitle(file.getOriginalFilename());
uploadedVideo.setSnippet(snippet);
InputStreamContent mediaContent =
new InputStreamContent("application/octet-stream",
new BufferedInputStream(file.getInputStream()));
YouTube.Videos.Insert videoInsert = youtubeService.videos()
.insert("snippet,status,id,player", uploadedVideo, mediaContent);
MediaHttpUploader uploader = videoInsert.getMediaHttpUploader();
uploader.setDirectUploadEnabled(false);
MediaHttpUploaderProgressListener progressListener = e -> {
switch (e.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: " + e.getProgress());
break;
case MEDIA_COMPLETE:
System.out.println("Upload Completed!");
break;
case NOT_STARTED:
System.out.println("Upload Not Started!");
break;
}
};
uploader.setProgressListener(progressListener);
return videoInsert.execute();
}
/**
* 获取视频列表
* @param uid
* @return
* @throws IOException
*/
@GetMapping(value = "/videoList")
@ResponseBody
public String getVideoList(String uid) throws IOException {
// 获取凭证
/* TokenResponse tokenResponse = JSON.parseObject("{\n" +
" \"access_token\": \"ya29.a0AX9GBdWDTl_WDHjAhMhqfHOv8Tee5o3Y8G-Un46rjLxVIXMBaUC8aUHzQWtwCzENq9EBPkN5WoXgiIgReOmBhEjIzJgZ3ZAbQt0em3m5NNFQe6LtL3Z0oj6UMHYHd0H4UJ2_N5Td1g3ggudW_539A09HtTV2aCgYKAdcSARASFQHUCsbCk4dDMR9R3-VivIgsglOayw0163\",\n" +
" \"expires_in\": 3599,\n" +
" \"refresh_token\": \"1//0eggCEbOSfmnnCgYIARAAGA4SNwF-L9IryVDE5t8GTDyOVAzPOPFc-TGJmiZOkUkzTVPLZuYMNOURZYA2fklO1_nhlSy3SOAsU4w\",\n" +
" \"scope\": \"https://www.googleapis.com/auth/youtubepartner https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtubepartner-channel-audit https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtubepartner-content-owner-readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube.channel-memberships.creator\",\n" +
" \"token_type\": \"Bearer\"\n" +
"}",TokenResponse.class);
Credential credential = flow.createAndStoreCredential(tokenResponse,uid);
*/
Credential credential = YoutubeAuthController.CREDENTIAL_MAP.get(uid);
YouTube youtubeService = new YouTube.Builder(httpTransport, jsonFactory, credential).build();
String part = "contentDetails,fileDetails,id,liveStreamingDetails,localizations,player,processingDetails,recordingDetails,snippet,statistics,status,suggestions,topicDetails";
String videoId = "sYljcKUToF0";
VideoListResponse listResp = youtubeService.videos().list(part).setId(videoId).execute();
System.out.println(JSON.toJSONString(listResp));
return JSON.toJSONString(listResp);
}
}
请理解上面这段代码,以上便是访问YouTube的Api全部内容了,注意Google应用对接口的访问有配额限制,限制每日配额是1w , 其中 查询消耗配额为 1,新增修改删除消耗配额为50,上传视频消耗1600配额,超过配额接口将不可访问,需要申请提高配额,
另外上传的视频是有格式限制的:文章来源:https://www.toymoban.com/news/detail-669384.html
YouTube支持的视频格式:文章来源地址https://www.toymoban.com/news/detail-669384.html
.MOV | .MP4 | .3GPP | .MPEGPS |
---|---|---|---|
.MPEG-1 | .MPG | .WebM | .FLV |
.MPEG-2 | .AVI | .DNxHR | .ProRes |
.MPEG4 | .WMV | .CineForm | .HEVC (h265) |
到了这里,关于对接YouTube平台实现上传视频——Java实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!