Docking YouTube platform to upload video - Java implementation

background description

Some time ago, the company requested to connect to the overseas YouTube platform to implement the video upload function. Since the description of the overseas documents was not detailed and my English skills were not good, I encountered many pitfalls in the process. I wrote this article in the hope that it can help those in need.

Preparation for docking with YouTube platform

Development environment : idea, jdk1.8, maven

Development preparation :

  1. Requires a Google account
  2. You need to log in to the Google console to create an application to enable the YouTube platform Api
  3. You need to go to the Google console to download the client_secrets.json file

Here is a graphic tutorial:

  1. Google console Create application
    Create app1.1 Select application type
    insert image description here1.2 client_secrets.json file
    insert image description here2. Enable YouTube's API
    insert image description here2.1 Enable this API
    insert image description hereenvironment After the environment is ready, let's first understand the access process

Access process

Calling YouTube Api requires Google OAuth2.0 authorization. After the authorization is completed, Google will return an access token to you. You can access Google Api within the validity period of the token. YouTube Api is a type of Google Api.
Let’s take a look at the authorization process of Google OAuth2.0:

  1. The application initiates a user authorization request for the application to the Google oaAuth2 server, and uses Google API to return to the application a link for the user to authorize the application.
  2. After the user opens the authorization link in the browser, selects the permissions granted to the application and clicks OK, Google oaAuth2 will call back the callback address configured by the application in the Google backend.
  3. The Google oaAuth server callback application interface will return the user authorization code (code) and the permissions (scope) given by the user to the application. After obtaining the user authorization code, the application initiates a request to the GoogleoaAuth server to exchange the user authorization code into a token.
  4. After getting the token returned by the oaAuth server, you can access the YouTube API. It should be noted here that the token returned by the Google oaAuth2 server has a time limit. The expiration time can be set in the Google backend. When the token expires, you need to hold the Google oaAuth2 The refresh_token in the token re-applies for a token from the Google oaAuth2 server

insert image description hereAfter understanding the process, we can officially enter the development

code development

  1. maven coordinates
<!-- 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>
  1. Configuration class
// 基础配置
@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();
    }

}

  1. Obtain Google authorization
@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);
    }
}

Remember: the same account can only authorize an application once. If you authorize the same account again, an error will be reported. Please understand this code first and understand what I mean, and then write your own code. Do not copy blindly!!!

After getting the access token, you can access YouYube's api.
Let's try to operate the code of the YouTube video interface.

@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);
    }
}

Please understand the above code. The above is the entire content of the API for accessing YouTube. Note that there is a quota limit for Google application access to the interface. The daily quota limit is 1w, of which the query consumption quota is 1, and the new modification and deletion consumption quota is 50. Uploading a video consumes 1600 quotas. If the quota exceeds the quota, the interface will not be accessible. You need to apply for an increase in the quota.
In addition, the uploaded video has a format limit:

Video formats supported by YouTube:

.MOV .MP4 .3GPP .MPEGPS
.MPEG-1 .MPG .WebM .FLV
.MPEG-2 .AVI .DNxHR .ProRes
.MPEG4 .WMV .CineForm .HEVC (h265)

Guess you like

Origin blog.csdn.net/weixin_44809686/article/details/128732733