背景描述
前段時間公司要求對接海外YouTube平臺實現視頻上傳的功能,由于海外文檔描述不詳細,且本人英語功底不好,過程中踩了很多坑,寫出這篇文章出來希望能幫助到有需要的人。
對接YouTube平臺的準備
開發(fā)環(huán)境:idea 、jdk1.8、maven
開發(fā)準備:
- 需要一個Google賬號
- 需要登錄到Google控制臺創(chuàng)建應用開啟YouTube平臺Api
- 需要需要去Google控制臺下載client_secrets.json文件
下面是圖文教程:
-
Google控制臺 創(chuàng)建應用
1.1 選擇應用類型
1.2 client_secrets.json文件
2.開啟YouTube的Api
2.1 啟用此api
環(huán)境準備好后咱們先了解一下接入流程
接入流程
調用YouTube Api需要用到Google OAuth2.0 授權,授權完成之后Google會返回給你一個訪問令牌,在令牌有效期內可以訪問Google Api 而 YouTube Api就是Google Api 下的一種。
下面來看下Google OAuth2.0的授權流程:
- 應用向Google oaAuth2服務器發(fā)起對用戶對該應用的授權請求,利用Google Api返回給應用一個用于用戶給應用授權的鏈接
- 用戶在瀏覽器打開授權鏈接后選擇授權給應用的權限后點擊確定,Google oaAuth2會回調該應用配置在谷歌后臺的回調地址
- Google oaAuth服務器回調應用接口會返回用戶授權碼(code)以及用戶給應用賦予的權限(scope),應用拿到用戶授權碼之后向GoogleoaAuth服務器發(fā)起請求把用戶授權碼兌換成令牌
- 拿到oaAuth服務器返回的令牌之后就能夠訪問YouTube的API了,這里要注意Google oaAuth2服務器返回的令牌是有時間限制的在谷歌后臺可以設置過期時間,當令牌過期后需要拿著Google oaAuth2令牌里面的refresh_token向Google oaAuth2服務器重新申請令牌
了解完流程之后咱們可以正式進入開發(fā)了
代碼開發(fā)
- 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配額,超過配額接口將不可訪問,需要申請?zhí)岣吲漕~,
另外上傳的視頻是有格式限制的:文章來源:http://www.zghlxwxcb.cn/news/detail-669384.html
YouTube支持的視頻格式:文章來源地址http://www.zghlxwxcb.cn/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模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!