使用Youtube官方API订阅功能的实现

对应个人站点文章:https://fengling.site/index.php/archives/33.html

在开篇之前,请允许我引用并重新组织一位博主的言语:若想实现对一个YouTube频道的订阅功能,目前所知有两种方法。
1. 采用直接而笨重的轮询机制 - 即每隔一段时间去请求频道下的视频接口,根据返回的视频名称判断是否是新视频。这样做的缺点显而易见,一是除非轮询时间间隔特别短,否则基本没法保证时效性。二是频繁的访问查询接口会浪费掉大量的api 配额,因此这不是一种优雅的解决方案。
2. 使用官方的发布订阅系统 - 一种基于Webhooks实现的订阅推送(对于Webhooks机制不清楚的同学可以了解后再去尝试),可以实现几乎实时的更新推送

部分内容引用自以下博客,本篇博客也就是对以下文章中第三点(订阅功能实现)的补充说明

https://blog.csdn.net/zzz_zjz/article/details/105006921

详细资料参考官方的这篇文档

https://developers.google.com/youtube/v3/guides/push_notifications

其主要流程就是,在下面这个网址中添加订阅频道和回调地址

https://pubsubhubbub.appspot.com/subscribe

订阅界面
这样你就会在你的服务器上接收到这样的更新信息

<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015"
         xmlns="http://www.w3.org/2005/Atom">
  <link rel="hub" href="https://pubsubhubbub.appspot.com"/>
  <link rel="self" href="https://www.youtube.com/xml/feeds/videos.xml?channel_id=CHANNEL_ID"/>
  <title>YouTube video feed</title>
  <updated>2015-04-01T19:05:24.552394234+00:00</updated>
  <entry>
    <id>yt:video:VIDEO_ID</id>
    <yt:videoId>VIDEO_ID</yt:videoId>
    <yt:channelId>CHANNEL_ID</yt:channelId>
    <title>Video title</title>
    <link rel="alternate" href="http://www.youtube.com/watch?v=VIDEO_ID"/>
    <author>
     <name>Channel title</name>
     <uri>http://www.youtube.com/channel/CHANNEL_ID</uri>
    </author>
    <published>2015-03-06T21:40:57+00:00</published>
    <updated>2015-03-09T19:05:24.552394234+00:00</updated>
  </entry>
</feed>
除以上资料外并没有更多像具体怎么实现的信息了,我想看到这像我一样的Java新手来言简直就是一头雾水。
为此我在此贴上我为时两个星期的测试代码(还是因为公司事务较忙,没空去查看日志所致)
以下代码只做测试、研究使用,生产环境勿用
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;

/**
 * @author 枫铃也
 * @time 2020-05-14 14:59
 * @description YouTube订阅服务接口 https://pubsubhubbub.appspot.com/subscribe
 */
@RestController
@RequestMapping("/system/youtube")
@Api(tags = "YouTubePubSubHubbubController")
public class YouTubePubSubHubbubController {

    private static final Logger LOGGER = LoggerFactory.getLogger(YouTubePubSubHubbubController.class);

    @RequestMapping(value = "subscribe", method = {RequestMethod.GET, RequestMethod.POST})
    @ApiOperation(value = "YouTube订阅认证接口", notes = "YouTube订阅认证接口")
    public String subscribe(HttpServletRequest request, @RequestHeader Map<String, String> headers) {
        LOGGER.info("----------------打印请求全部消息开始----------------");
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            LOGGER.info("{} - {}", name, request.getHeader(name));
        }
        LOGGER.info("----------------打印请求全部消息结束----------------");
        LOGGER.info("-----------------打印请求头消息开始-----------------");
        headers.forEach((String key, String value) -> LOGGER.info(String.format("Header '%s' = %s", key, value)));
        LOGGER.info("-----------------打印请求头消息结束-----------------");
        Map<String, String[]> parameterMap = request.getParameterMap();
        LOGGER.info("------------------打印全部参数开始------------------");
        String result = "";
        if (parameterMap.isEmpty()) {
            LOGGER.info("请求参数为空");
        }else {
            parameterMap.forEach((String key, String[] value) -> {
                for (String s : value) {
                    LOGGER.info("Param '{}' = {}", key, s);
                }
            });
            result = parameterMap.get("hub.challenge")[0];
        }
        LOGGER.info("------------------打印全部参数结束------------------");
        LOGGER.info("-----------------打印Reader数据开始----------------");
        StringBuilder buffer = new StringBuilder();
        try (BufferedReader reader = request.getReader()){
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        }
        LOGGER.info("reader -> {}", buffer);
        LOGGER.info("-----------------打印Reader数据结束----------------");
        return result;
    }
}

请大家忽略以上代码中的日志和API文档生成的辅助类,并附上实践 具体 完装的日志输出

09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - ----------------打印请求全部消息开始----------------
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - host - 这个我不能给你们看,嘿嘿嘿
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - link - <https://www.youtube.com/xml/feeds/videos.xml?channel_id=UCXQexglLCaJyTImYLmSO9Ng>; rel=self, <http://pubsubhubbub.appspot.com/>; rel=hub
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - content-type - application/atom+xml
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - cache-control - no-cache,max-age=0
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - pragma - no-cache
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - content-length - 943
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - connection - keep-alive
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - accept - */*
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - from - googlebot(at)googlebot.com
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - user-agent - FeedFetcher-Google; (+http://www.google.com/feedfetcher.html)
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - accept-encoding - gzip,deflate,br
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - ----------------打印请求全部消息结束----------------
09:39:30.330 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - -----------------打印请求头消息开始-----------------
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'host' = 这个我不能给你们看,嘿嘿嘿
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'link' = <https://www.youtube.com/xml/feeds/videos.xml?channel_id=UCXQexglLCaJyTImYLmSO9Ng>; rel=self, <http://pubsubhubbub.appspot.com/>; rel=hub
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'content-type' = application/atom+xml
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'cache-control' = no-cache,max-age=0
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'pragma' = no-cache
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'content-length' = 943
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'connection' = keep-alive
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'accept' = */*
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'from' = googlebot(at)googlebot.com
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'user-agent' = FeedFetcher-Google; (+http://www.google.com/feedfetcher.html)
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - Header 'accept-encoding' = gzip,deflate,br
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - -----------------打印请求头消息结束-----------------
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - ------------------打印全部参数开始------------------
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - 请求参数为空
09:39:30.331 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - ------------------打印全部参数结束------------------
09:39:30.332 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - -----------------打印Reader数据开始----------------
09:39:30.332 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - reader -> <?xml version='1.0' encoding='UTF-8'?><feed xmlns:yt="http://www.youtube.com/xml/schemas/2015" xmlns="http://www.w3.org/2005/Atom"><link rel="hub" href="https://pubsubhubbub.appspot.com"/><link rel="self" href="https://www.youtube.com/xml/feeds/videos.xml?channel_id=UCXQexglLCaJyTImYLmSO9Ng"/><title>YouTube video feed</title><updated>2020-05-28T01:39:27.887188153+00:00</updated><entry>  <id>yt:video:GRrUhlU34GM</id>  <yt:videoId>GRrUhlU34GM</yt:videoId>  <yt:channelId>UCXQexglLCaJyTImYLmSO9Ng</yt:channelId>  <title>Dota2 - Team Nigma vs. Gambit - Game 3 - ESL One Birmingham 2020 - Group B - EU/CIS</title>  <link rel="alternate" href="https://www.youtube.com/watch?v=GRrUhlU34GM"/>  <author>   <name>ESL Archives</name>   <uri>https://www.youtube.com/channel/UCXQexglLCaJyTImYLmSO9Ng</uri>  </author>  <published>2020-05-28T01:36:33+00:00</published>  <updated>2020-05-28T01:39:27.887188153+00:00</updated> </entry></feed>
09:39:30.332 [http-nio-4930-exec-7] INFO  o.f.m.i.y.c.s.YouTubePubSubHubbubController - -----------------打印Reader数据结束----------------
一行字数太多,若换行显示大家则可以复制到Notpad++或其他编辑器缩放显示

通过以上日志输出可以看出此订阅方式的参数并非是传统的from表单形式。到此,具体的代码实现也就没什么可写的了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章