home
打造视频下载Webhook
打造视频下载Webhook

# 前言

由于 B 站的番出现圣骑和被剪的情况越来越多,今年补番已经使用了别的方式,加之 B 站的客户端越更越烂,已经卡到在骁龙 636+原生上都不能流畅看视频了,用旧版本又看不了 1080p,于是我越来越想从手机里删掉这垃圾了。然而有些喜欢的 up 主只在 B 站传视频,那么有什么解决途径呢?

今年初我开始自建 RSSHub 订阅信息流,从手机里删掉了一大堆科技网站客户端,当然 B 站的 up 主更新也使用 RSSHub 订阅了,不过看还是得跳去客户端,前段时间看到 RSSHub 的作者搞了个用订阅触发 webhook 下载,然后用 you-get 下视频的小工具,然而是 nodejs 写的,youget 则是 python 写的,我的便宜小鸡跑个 RSSHub 和其他一些杂七杂八的东西已经把内存吃的差不多了,再跑个 node 怕是要炸,于是就没继续折腾,不过前两天突发奇想,要是使用 go rust 这些编译型语言写的工具实现同样的功能,应该没什么大问题吧!于是便有了本文。

# webhook

首先是搞定 webhook 部分,稍作搜索,果然有 go 写的 webhook 工具,而且提供了 Docker 镜像,我打算使用一堆小工具组合实现功能,但是不想创建多个 container,毕竟跨 container 要共享 volume 啥的也挺麻烦的。

所以先把他的镜像作为中间层引入,然后在一个新镜像里跑起来试试看。

FROM almir/webhook as builder

FROM alpine:latest
EXPOSE 9000
VOLUME /etc/webhook
COPY --from=builder /usr/local/bin/webhook /usr/bin/webhook
RUN chmod +x /usr/bin/webhook
ENTRYPOINT ["/usr/bin/webhook"]
CMD ["-verbose", "-hooks=/etc/webhook/hooks.json", "-hotreload"]
[
	{
		"id": "down",
		"execute-command": "/usr/bin/sh",
		"command-working-directory": "/etc/webhook",
		"pass-arguments-to-command": [
			{
				"source": "string",
				"name": "echo"
			},
			{
				"source": "url",
				"name": "url"
			}
		]
	}
]

Caddy 反代 9000 端口出去,请求一下/hooks/down?url=目标链接可以看到容器日志里会打印出链接。

# 视频下载

接下来要找个可以下载视频的东西,一番寻找之后找到了annie

功能很多,支持一堆下载网站,不过我只需要能下载 B 站的视频页就可以了,加入一个 builder 中间层,编译一波,然后塞镜像里:

FROM almir/webhook as webhook

FROM golang:1.12.4 as builder
RUN apk add --no-cache git
RUN go get -v github.com/iawia002/annie

FROM alpine:latest
EXPOSE 9000
VOLUME /etc/webhook
COPY --from=webhook /usr/local/bin/webhook /usr/bin/webhook
COPY --from=builder /go/bin/annie /usr/bin/annie
RUN chmod +x /usr/bin/webhook /usr/bin/annie
ENTRYPOINT ["/usr/bin/webhook"]
CMD ["-verbose", "-hooks=/etc/webhook/hooks.json", "-hotreload"]

annie 的下载进度是直接打印在控制台输出上的,想要看到进度会很麻烦,不过 annie 还支持调用 aria2 下载。

先从官方文档抄一个 aria2 的配置文件,省的在命令行上写一大堆参数:

dir=/etc/webhook/downloads
input-file=/etc/aria2.session
save-session=/etc/aria2.session

file-allocation=falloc
log-level=warn
enable-http-pipelining=true

max-concurrent-downloads=3
max-connection-per-server=10
min-split-size=10M
split=10
continue=true
max-overall-download-limit=0
max-overall-upload-limit=1K

enable-rpc=true
rpc-listen-all=true
rpc-allow-origin-all=true
rpc-listen-port=6800

disable-ipv6=true

然后继续修改 dockerfile,引入 aria2:

FROM almir/webhook as webhook

FROM golang:1.12.4 as builder
RUN apk add --no-cache git
RUN go get -v github.com/iawia002/annie

FROM alpine:latest
EXPOSE 9000 6800
VOLUME /etc/webhook
COPY --from=webhook /usr/local/bin/webhook /usr/bin/webhook
COPY --from=builder /go/bin/annie /usr/bin/annie
COPY ./aria2.conf /etc/aria2.conf
RUN apk add --no-cache aria2 tzdata && \
    chmod +x /usr/bin/webhook /usr/bin/annie && \
	touch /etc/aria2.session
ENTRYPOINT ["/usr/bin/webhook"]
CMD ["-verbose", "-hooks=/etc/webhook/hooks.json", "-hotreload"]

这时候已经需要同时运行两个程序了,写个 sh 跑不太稳定,而且只有最后一个运行的程序才能直接用docker logs看到日志,那就搜索下有什么比较好用的进程管理器吧。

试用了一堆后,选用了foreman的一个 go 移植版本goreman,这是一个管理基于Procfile启动的程序的管理器。

先写个 Procfile:

webhook:/usr/bin/webhook -verbose -hooks=/etc/webhook/hooks.json -template -hotreload
aria2c:/usr/bin/aria2c --conf-path=/etc/aria2.conf --log=/etc/webhook/logs.txt --rpc-secret=$RPC_SECRET

然后继续修改 dockerfile,编译 goreman 并引入:

FROM almir/webhook as webhook

FROM golang:1.12-alpine as builder
RUN apk add --no-cache git
RUN go get -v github.com/iawia002/annie
RUN go get -v github.com/mattn/goreman

FROM alpine:latest
EXPOSE 9000 6800
VOLUME /etc/webhook
ENV RPC_SECRET=""
COPY --from=webhook /usr/local/bin/webhook /usr/bin/webhook
COPY --from=builder /go/bin/annie /usr/bin/annie
COPY --from=builder /go/bin/goreman /usr/bin/goreman
COPY ./Procfile /etc/Procfile
COPY ./aria2.conf /etc/aria2.conf
RUN apk add --no-cache aria2 tzdata && \
    chmod +x /usr/bin/webhook /usr/bin/annie /usr/bin/goreman && \
	touch /etc/aria2.session
WORKDIR /etc
ENTRYPOINT ["/usr/bin/goreman"]
CMD ["start"]

最后我还需要一个 aria2 的网页端控制台,aria2-ng是使用人群中比较流行的客户端,界面挺不错。

这个控制台不需要后端,直接调用 aria2 jsonrpc,这个前面已经启用了。虽然网上有不少人利用 github pages 之类的静态页面服务提供在线版本,不过处理跨域也是比较麻烦,所以我打算直接在本地搭一个。

我在外部使用 caddy 将 10+ 容器服务反代到一个域名下,虽然 ariang 是一个纯 html 文件,可以直接把文件放到外面让 caddy 进行代理,但是这会让容器的重新部署变得麻烦,集成到容器里显然是更好选择。

darkhttpd是一个十分轻量级的静态 http 服务器,我直接使用它提供 http 服务,之后再在外部的 caddy 容器中进行反代。

基于上面的信息,继续修改 dockerfile:

FROM almir/webhook as webhook

FROM golang:1.12-alpine as builder
RUN apk add --no-cache curl git jq unzip
RUN go get -v github.com/iawia002/annie
RUN go get -v github.com/mattn/goreman
RUN mkdir -p /aria2-ng
RUN curl -o /aria2-ng.zip -L $(curl -sX GET "https://api.github.com/repos/mayswind/AriaNg/releases/latest" | jq -r '.assets[0].browser_download_url')
RUN unzip /aria2-ng.zip -d /aria2-ng
RUN sed -i 's/6800/443/g' /aria2-ng/index.html

FROM alpine:latest
EXPOSE 9000 6800 80
VOLUME /etc/webhook
ENV RPC_SECRET=""
COPY --from=webhook /usr/local/bin/webhook /usr/bin/webhook
COPY --from=builder /go/bin/annie /usr/bin/annie
COPY --from=builder /go/bin/goreman /usr/bin/goreman
COPY --from=builder /aria2-ng /etc/aria2-ng
COPY ./webhook.proc /etc/Procfile
COPY ./aria2.conf /etc/aria2.conf
RUN apk add --no-cache aria2 darkhttpd tzdata && \
    chmod +x /usr/bin/webhook /usr/bin/annie /usr/bin/goreman && \
	touch /etc/aria2.session
WORKDIR /etc
ENTRYPOINT ["/usr/bin/goreman"]
CMD ["start"]

然后修改 Procfile,顺便启用 rpc_secret:

webhook:/usr/bin/webhook -verbose -hooks=/etc/webhook/hooks.json -template -hotreload
darkhttpd:/usr/bin/darkhttpd /etc/aria2-ng --port 80
aria2c:/usr/bin/aria2c --conf-path=/etc/aria2.conf --log=/etc/webhook/logs.txt --rpc-secret=$RPC_SECRET

启用 rpc_secret 后,annie 的下载请求也要带上,这时候修改下 webhook 的请求参数:

[
    {
      "id": "down",
      "execute-command": "/usr/bin/annie",
      "command-working-directory": "/etc/webhook",
      "pass-arguments-to-command":
      [
        {
            "source": "string",
            "name": "-aria2"
        },
        {
            "source": "string",
            "name": "-aria2token"
        },
        {
            "source": "string",
            "name": "{{ getenv "RPC_SECRET" }}"
        },
        {
          "source": "url",
          "name": "url"
        }
      ]
    }
  ]

至此已经搞得差不多,再使用 caddy 反代一下就可以用了(tls 配置自行处理,否则把 https 改成 http):

https://your.domain {
  proxy /aria2 http://webhook:80 {
    without /aria2
  }
  proxy /jsonrpc http://webhook:6800 {
    websocket
  }
  proxy /hooks http://webhook:9000
}

现在可以使用/aria2 进入管理页面,aria2 的 rpc-secret 使用环境变量 RPC_SECRET 设置。 下载视频则直接 get 请求 /hooks/down?url=视频 url。

# 自动下载

最后的自动下载依然是使用 ifttt,订阅到新 rss 后直接把链接请求一下就好:

ifttt

# Docker 镜像

最后做了一下整理,publish 到了 Docker Hub 上。

直接运行:

docker run -d --name webhook -p 9000:9000 -p 6800:6800 -p 80:80 -e RPC_SECRET=<YOUR_RPC_SECRET> -e URL_PREFIX=<YOUR_WEBHOOK_URL_PREFIX> darkskydocker/down_webhook

docker-compose:

version: '2.3'
services:
    webhook:
        image: darkskydocker/down_webhook:latest
        environment:
            - RPC_SECRET=<YOUR_RPC_SECRET>
            - URL_PREFIX=<YOUR_WEBHOOK_URL_PREFIX>
        volumes:
            - ./webhook:/etc/webhook
        logging:
            options:
                max-size: '500k'
        restart: always