YouTube数据API(v3):Spring Boot简介

YouTube Data API (v3): Introduction With Spring Boot

Java YouTube Data API

YouTube是一个视频共享网站,用户可以在其中查看和上传视频。 对于Web和应用程序开发,有时我们需要访问YouTube视频中的信息。

在这种情况下,我们必须使用Google开发人员提供的API。 本文的主要目的是介绍如何将YoutTube API与Java结合使用。 在这里,我们将结合使用Spring Boot和Hibernate JPA以及Google提供的库来实现示例。

前提条件

要访问YouTube数据API,我们必须遵循一些基本说明,例如创建Google帐户,项目,凭据等。也许,最好遵循此处列出的这些说明。 如果遵循此链接中的步骤,则首先需要ClientId,API密钥,客户端密钥等。

接下来,我们可以开始执行。 我们需要将凭据放入application.properties文件中。 要运行GitHub示例(下面提供了链接),我们还需要设置Java,MySQL和Gradle。

提供文件

在本文中,我们主要关注视频信息。 YouTube视频属性主要包含频道,持续时间,描述和统计信息(喜欢,不喜欢等)。 这些属性在YouYube API的不同资源中可用,例如视频,频道,活动等。这些资源还可以执行列表,插入,更新和删除操作。

本教程的最后一部分将是自定义YouYube API,以便我们可以定义所需的内容。 就像统计信息部分仅包含喜欢,不喜欢,综合浏览量等,contentDetails部分仅包含视频定义,字幕,国家/地区限制等? —所有这些组件都包含嵌套对象。 结合起来,我们可以获得视频的所有属性,但是在这里,我们将只关注重要的部分。

实作

话虽如此,我们将以一些不同的方式实现YouTube数据API。 我们将使用REST API将提取的数据保存到数据库。 对于数据库实体,我们将创建一个相应的JPA实体。 我们已根据不同部分划分了大多数视频属性。 实体是:

  • YoutubeChannelInfo

  • YouTubevideoInfo

  • Youtubevideostatistics

  • 此外,我们将拥有一个用于公共属性的BaseEntity,以及另一个实体(CrawlingInfo)来跟踪已爬网的数据。

    我们将收集以下数据作为渠道信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @Entity(name ="youtube_channel")
    @Data
    @EqualsAndHashCode(callSuper=true)
    public class YoutubeChannelInfo extends BaseEntity{

        @Column(name ="channel_id")
        private String channelId;
        @Column(name ="name")
        private String name;
        @Column(name ="subscription_count")
        private long subscriptionCount;
    }

    对于视频统计信息,我们将收集以下数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @Entity(name ="youtube_video_stat")
    @Data
    @EqualsAndHashCode(callSuper=true)
    public class Youtubevideostatistics extends BaseEntity{

        @Column(name ="like_count")
        private long likeCount;

        @Column(name ="dislike_count")
        private long dislikeCount;

        @Column(name ="view_count")
        private long viewCount;

        @Column(name ="favourite_count")
        private long favouriteCount;

        @Column(name ="comment_count")
        private long commentCount;

        @Column(name ="video_id")
        private String videoId;
    }

    对于常见的视频属性,我们将收集以下数据:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    @Entity(name ="youtube_video_info")
    @Data
    @EqualsAndHashCode(callSuper=true)
    public class YouTubevideoInfo extends BaseEntity{

        @Column(name ="video_id")
        private String videoId;

        @Column(name ="title")
        private String title;

        @Column(name ="thumbnail_url")
        private String thumbnailUrl;


        @Column(name ="description")
        private String description;

        @Column(name ="published_date")
        private Date publishedDate;

        @Column(name ="definition")
        private String videoDefinition;

        @Column(name ="duration")
        private String videoDuration;

        @Column(name ="caption")
        private String videoCaption;

        @Column(name ="projection")
        private String videoprojection;

        @Column(name ="country_restricted")
        private String countryRestricted;

        @Column(name ="keyword")
        private String keyword;

        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumn(name ="channel_id",referencedColumnName ="channel_id")
        private YoutubeChannelInfo channelInfo;

        @OneToOne(fetch = FetchType.LAZY)
        @JoinColumn(name ="video_stat_id",referencedColumnName ="video_id")
        private Youtubevideostatistics videostatistics;
    }

    现在,我们将通过YouTube数据API获取视频信息。 因此,我们需要Google团队提供的一些库。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    compile group: 'com.google.api-client', name: 'google-api-client', version: '1.25.0'
    compile group: 'com.google.apis', name: 'google-api-services-youtube', version: 'v3-rev212-1.25.0'
    compile group: 'com.google.apis', name: 'google-api-services-youtubeAnalytics', version: 'v1-rev14-1.13.2-beta'
    compile group: 'com.google.apis', name: 'google-api-services-youtubereporting', version: 'v1-rev1-1.20.0'
    compile("com.google.oauth-client:google-oauth-client-jetty:1.25.0") {
    exclude group: 'org.mortbay.jetty', module: 'servlet-api'
    }
    compile group: 'com.google.http-client', name: 'google-http-client-jackson2', version: '1.25.0'
    compile group: 'com.google.collections', name: 'google-collections', version: '1.0'

    其他库也用于Spring Boot和数据库支持。 我们可以在" gradle file"找到这些库。

    首先,我们必须初始化?YouTube(v3)属性,以支持YouTube的核心功能,例如上传视频,创建和管理播放列表,搜索内容等等。 但是在这里,我们将首先实现一些基本属性。

    1
    2
    3
    4
    5
    6
         youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, new HttpRequestInitializer() {
                    public void initialize(HttpRequest request) throws IOException {
          }
         }).setApplicationName("YouTubevideoInfo")
           .setYouTubeRequestInitializer
           (new YouTubeRequestInitializer(env.getProperty("youtube.apikey"))).build();

    创建凭据时,我必须创建一个分配为应用程序名称的应用程序名称YouTubevideoInfo。 属性 youtube.apikey 位于 application.properties 文件中。 我们必须将youtube.apikey的值替换为我们的值。

    现在,我们将以此获取一些信息。 最初,我们使用id, snippet来获取一些基本数据。

    1
    2
    3
    4
    5
    6
    7
    YouTube.Search.List search = youtube.search().list("id,snippet");
    //search keyword eg."IELTS"
    search.setQ(queryTerm);
    //return only video type data
    search.setType("video");
    // number of video data return. maximum 50
    search.setMaxResults(NUMBER_OF_videoS_RETURNED);

    在这里,queryTerm将是我们的搜索关键字,video 将是将返回视频类型数据信息的数据类型。 在youtube API列表请求中,最多返回50个视频信息作为响应。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     SearchListResponse searchResponse = search.execute();

    List<SearchResult> searchResultList = searchResponse.getItems();
    if (searchResultList != null) {
      extractAndSave(searchResultList.iterator(), queryTerm);
      }

    CrawlingInfo.setnextPageToken(searchResponse.getnextPageToken());
    CrawlingInfoService.update(CrawlingInfo);
    System.out.println("Next Page token :" + searchResponse.getnextPageToken());

    在此,?the search.execute()方法将返回预期结果。 因此,我们必须解析此响应。 还有一件事:CrawlingInfo类将用于维护下一页和上一页。 YouTube API在带有下一页令牌的请求中最多返回50条数据。 如果要访问下一页,则必须根据需要在pageToken属性中添加nextPageToken,然后它将移至下一页。 这就是为什么我们使用CrawlingInfo ?entity保持跟踪的原因。

    我们将对其余代码使用更多查询,以提取每个视频的频道信息,内容详细信息,统计信息等,然后保存到数据库中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    public List<Object> getYoutubevideoList(String queryTerm,long pageToCrawl) {

            try {

                youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, new HttpRequestInitializer() {
                    public void initialize(HttpRequest request) throws IOException {
                    }
                }).setApplicationName("YouTubevideoInfo")
                        .setYouTubeRequestInitializer(new YouTubeRequestInitializer(env.getProperty("youtube.apikey"))).build();

                YouTube.Search.List search = youtube.search().list("id,snippet");


                search.setQ(queryTerm);
                search.setType("video");
                search.setMaxResults(NUMBER_OF_videoS_RETURNED);

                for (int i = 0; i < pageToCrawl; i++) {
                    String pageToken = null;
                    CrawlingInfo CrawlingInfo = CrawlingInfoService.getBySearchKey(queryTerm);
                    if (CrawlingInfo != null && CrawlingInfo.getnextPageToken() != null) {
                        pageToken = CrawlingInfo.getnextPageToken();
                        count = CrawlingInfo.getTotalCount();
                        CrawlingInfo.setCurrentpageToken(pageToken);
                    } else if (CrawlingInfo == null) {
                        CrawlingInfo = new CrawlingInfo();
                        count = 0;
                        CrawlingInfo.setSearchKey(queryTerm);
                        CrawlingInfo.setCurrentpageToken(null);
                    }

                    if (pageToken != null) {
                        search.setpageToken(pageToken);
                    }


                    SearchListResponse searchResponse = search.execute();

                    List<SearchResult> searchResultList = searchResponse.getItems();
                    if (searchResultList != null) {
                        extractAndSave(searchResultList.iterator(), queryTerm);
                    }

                    CrawlingInfo.setnextPageToken(searchResponse.getnextPageToken());

                    CrawlingInfoService.update(CrawlingInfo);

                    System.out.println("Next Page token :" + searchResponse.getnextPageToken());
                }
            } catch (GoogleJsonResponseException e) {
                System.err.println("There was a service error:" + e.getDetails().getCode() +" :"
                        + e.getDetails().getMessage());
            } catch (IOException e) {
                System.err.println("There was an IO error:" + e.getCause() +" :" + e.getMessage());
            } catch (Throwable t) {
                t.printStackTrace();
            }
            return null;
        }

    private void extractAndSave(Iterator<SearchResult> iteratorSearchResults, String query) throws IOException {

            if (!iteratorSearchResults.hasNext()) {
                System.out.println(" There aren't any results for your query.");
            }

            while (iteratorSearchResults.hasNext()) {

                SearchResult singlevideo = iteratorSearchResults.next();

                System.out.println("video number =" + count +" Inserting video Information" + singlevideo.getId().getvideoId());
                count++;
                YouTubevideoInfo YouTubevideoInfo = YouTubevideoInfoService.getByvideoId(singlevideo.getId().getvideoId());

                if (YouTubevideoInfo == null) {
                    YouTubevideoInfo = new YouTubevideoInfo();
                    ResourceId rId = singlevideo.getId();

                    YouTubevideoInfo.setKeyword(query);
                    YouTubevideoInfo.setDescription(singlevideo.getSnippet().getDescription());
                    YouTubevideoInfo.setPublishedDate(new Date(singlevideo.getSnippet().getPublishedAt().getValue()));

                    if (rId.getKind().equals("youtube#video")) {
                        Thumbnail thumbnail = singlevideo.getSnippet().getThumbnails().getDefault();
                        YouTubevideoInfo.setvideoId(rId.getvideoId());
                        YouTubevideoInfo.setTitle(singlevideo.getSnippet().getTitle());
                        YouTubevideoInfo.setThumbnailUrl(thumbnail.getUrl());

                        YouTubevideoInfo.setChannelInfo(getChannelDetailsById(singlevideo.getSnippet().getChannelId()));

                        YouTubevideoInfo.setvideostatistics(getvideosstatistics(rId.getvideoId()));
                    }

                    YouTubevideoInfoService.save(YouTubevideoInfo);
                } else {
                    System.out.println("video Already exists...");
                }


            }
        }

        private YoutubeChannelInfo getChannelDetailsById(String channelId) throws IOException {
            YouTube.Channels.List channels = youtube.channels().list("snippet, statistics");

            YoutubeChannelInfo youtubeChannelInfo = new YoutubeChannelInfo();
            youtubeChannelInfo.setChannelId(channelId);
            channels.setId(channelId);
            ChannelListResponse channelResponse = channels.execute();
            Channel c = channelResponse.getItems().get(0);

            youtubeChannelInfo.setName(c.getSnippet().getTitle());
            youtubeChannelInfo.setSubscriptionCount(c.getstatistics().getSubscriberCount().longValue());

            YoutubeChannelInfo channelInfo = youtubeChannelService.getByChannelId(channelId);

            if (channelInfo == null) {
                youtubeChannelService.save(youtubeChannelInfo);
            } else {
                return channelInfo;
            }
            return youtubeChannelInfo;
        }


        public Youtubevideostatistics getvideosstatistics(String id) throws IOException {
            YouTube.videos.List list = youtube.videos().list("statistics");
            list.setId(id);
            video v = list.execute().getItems().get(0);

            Youtubevideostatistics statistics = new Youtubevideostatistics();

            statistics.setvideoId(id);
            statistics.setLikeCount(v.getstatistics().getLikeCount() !=null ? v.getstatistics().getLikeCount().longValue():0);
            statistics.setDislikeCount(v.getstatistics().getDislikeCount() != null ? v.getstatistics().getDislikeCount().longValue():0);
            statistics.setFavouriteCount(v.getstatistics().getFavoriteCount() != null ? v.getstatistics().getFavoriteCount().longValue():0);
            statistics.setCommentCount(v.getstatistics().getCommentCount() != null ? v.getstatistics().getCommentCount().longValue() : 0);
            statistics.setViewCount(v.getstatistics().getViewCount() != null ? v.getstatistics().getViewCount().longValue() : 0);


            youtubevideoStatService.save(statistics);

            return statistics;
        }


        public YouTubevideoInfo getCoontentDetails(String id, YouTubevideoInfo YouTubevideoInfo) throws IOException {
            YouTube.videos.List list = youtube.videos().list("contentDetails");
            list.setId(id);
            video v = list.execute().getItems().get(0);
            YouTubevideoInfo.setvideoDefinition(v.getcontentDetails().getDefinition());
            YouTubevideoInfo.setvideoCaption(v.getcontentDetails().getCaption());
            YouTubevideoInfo.setvideoprojection(v.getcontentDetails().getProjection());
            YouTubevideoInfo.setCountryRestricted(v.getcontentDetails().getCountryRestriction().toPrettyString());

            return YouTubevideoInfo;
        }

    如果我们看一下前面的代码片段,我们可以看到,对于statisticscontentDetails,我们正在使用视频资源和列表操作。 对于频道信息,我们正在使用频道资源和列表操作。 在这里,我代表了YouTube数据API的所有列表操作。 通过类似的方法,我们可以顺利使用其他操作。

    这里提供了本文的代码示例。-

    进一步阅读

    使用Spring Data JPA和Hibernate构建Spring Boot API

    YouTube Java API入门