用openresty(Lua)写一个获取YouTube直播状态的接口

之前在QQ机器人上面加了个虚拟主播开播提醒的功能(群261037783),我直接用caddy反代来获取YouTube页面的信息。由于是定时轮询一大堆人,而且是下载整个页面的内容,所以延迟极高。
被某人调侃的群名:

所以我决定写一个接口,直接由服务器来判断状态,并把结果传给机器人,这样会省下很多时间和流量。

网页接口选择有不少,可以直接php,也可以搞python或者.net来写,不过经过多方面的考虑,我决定使用OpenResty来实现这个功能。

OpenResty

实际上这个反代就是在nginx的基础上,加上了Lua功能。也正是因为这样,我可以直接用Lua脚本来写一个接口,完全不需要使用后端的东西,而且资源占用极低。。

开搞

配置

新建一个虚拟主机,往里面扔上自己lua脚本的设置:

    #youtube接口
    location /api {
        default_type application/json;
        content_by_lua_file /www/wwwroot/xxx.xxx.com/api.lua;
    }

然后去改这个脚本文件就好了

安装lua依赖

由于需要https下载功能来获取页面信息,我们直接用luarocks装两个东西就好了

如果你没装过luarocks,请自行使用apt-get install luarocksyum install luarocks进行安装

我们需要安装下面两个组件:

luarocks install luaSec
luarocks install httpclient

然后还需要一个json库,随便找一个就好了,放到合适的目录下面,例如下载下面这个脚本:

https://github.com/chenxuuu/receiver-meow/blob/master/appdata/lua/require/JSON.lua

写功能

写功能就很随意了,我现在写的是,传入一个c=xxx的值,xxx为频道号,返回开播信息的json信息即可:

package.path = package.path..";/www/wwwroot/xxx.xxx.com/?.lua"
--包位置,用来引用json库
json = require("JSON")

channel = ngx.req.get_uri_args()["c"]
if not channel then ngx.say(json:encode({error = "no c found"})) return end

hc = require('httpclient').new()
res = hc:get("https://www.youtube.com/channel/"..channel.."/live")
if not res.body then ngx.say(json:encode({error = res.err})) return end

if ngx.req.get_uri_args()["debug"] == "on" then
    ngx.say(res.body)
    return
end

local ytplayer_config = res.body:match("ytplayer.config *= *(.-});")
if not ytplayer_config then ngx.say(json:encode({error = "no this channel"})) return end
local info = json:decode(json:decode(ytplayer_config)['args']['player_response'])

local result = {}
result.live = info.videoDetails.isLive
result.title = info.videoDetails.title
result.url = "https://youtu.be/"..info.videoDetails.videoId
result.thumbnail = info.videoDetails.thumbnail.thumbnails[#info.videoDetails.thumbnail.thumbnails].url
result.channel = info.videoDetails.channelId

ngx.say(json:encode(result))

使用

效果相当好嘛:

检测每个频道的时间,由之前的十几秒或者几十秒,缩短到了一秒多

1 Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注