使用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表單形式。到此,具體的代碼實現也就沒什麼可寫的了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章