一系列简陋的 Bash 脚本,可以实现 YouTube、OPENREC、Twitch、TwitCasting 等平台主播开播时自动录像。
因为我喜欢的 VTuber 神楽めあ 是个喜欢突击直播还不留档的惯犯,所以我写了这些脚本挂在 VPS 上监视直播动态,一开播就自动开始录像,这样就算错过了直播也不用担心。
脚本的工作原理很简单,就是每过 30s 检查一次直播状态(这个延迟可以在脚本中的 sleep 30
处调节),如果在播就开始录像,没在播就继续轮询,非常简单粗暴(因为我懒得用 PubSubHubbub,而且我这台 VPS 就是专门为了录 mea 买的,所以不用在意性能之类的问题)。
这些脚本支持的直播平台基本上覆盖了 mea 的活动范围,如果有其他希望支持的平台也可以开 issue。
本脚本依赖以下程序,请自行安装并保证能在 $PATH
中找到。
- ffmpeg
- youtube-dl
- streamlink
需要注意的是,各大 Linux 发行版官方软件源中的 ffmpeg 版本可能过旧(3.x 甚至 2.x),录像时会出现奇怪的问题,推荐在 这里 下载最新版本(4.x)的预编译二进制文件。
youtube-dl 和 streamlink 都可以直接使用 pip 进行安装。
./record_youtube.sh url [format] [loop|once]
# Example
./record_youtube.sh "UCWCc8tO-uUl_7SJXIKJACMw"
./record_youtube.sh "https://www.youtube.com/channel/UCWCc8tO-uUl_7SJXIKJACMw/live" best loop
./record_youtube.sh "https://www.youtube.com/watch?v=NeQrejV3JnE" best once
./record_youtube.sh "https://youtu.be/WMu7SGeUTG4" "bestvideo[height<=480]+bestaudio"
第一个参数为 YouTube 频道 ID(就是频道 URL youtube.com/channel
后面的那个),或者待机室的 URL(即在频道 URL 后面添加 /live
),这样可以实现无人值守监视开播。参数也可以是某次直播的直播页面 URL(如示例三),不过这样就只能对这一场直播进行录像,录不到该频道的后续直播,所以推荐使用前者。
第二个参数为可选参数,指定录像的画质,不指定的话默认以最高不大于 720p 的格式录像(即 best[height<=720]
)。指定为 best
即可使用可用的最高画质进行录像(注意机器硬盘空间),更多可以使用的格式字符串请参考 youtube-dl -f
参数的文档。
第三个参数为可选参数,如果指定为 once
,那么当前直播的录像完成后脚本会自动退出,而不会继续监视后续直播。
录像文件默认保存在脚本文件所在的目录下,文件名格式为 youtube_{id}_YYMMDD_HHMMSS.ts
。输出的视频文件使用 MPEG-2 TS 容器格式保存,因为 TS 格式有着可以从任意位置开始解码的优势,就算录像过程中因为网络波动等问题造成了中断,也不至于损坏整个视频文件。如果需要转换为 MP4 格式,可以使用以下命令:
ffmpeg -i xxx.ts -codec copy xxx.mp4
另外,当前直播的元信息(包括标题、概要栏等)保存在 视频文件名.info.json
文件中,录像时 ffmpeg 进程的详细输出会写入至 视频文件名.log
日志文件,使用 tail -f xxx.log
命令可以实时查看。
./record_openrec.sh openrec_id [format] [loop|once]
# Example
./record_openrec.sh KaguraMea 480p
./record_openrec.sh 23_kanae best once
此脚本依赖 curl 以从用户频道页面获取当前的直播信息。
第一个参数为 OPENREC 用户名,就是用户主页 URL 中 openrec.tv/user
后面的那个。
第二个参数为可选参数,指定录像的画质,不指定的话默认以最高不大于 720p 的格式录像(即 720p,480p,best
)。指定为 best
即可使用可用的最高画质进行录像(注意机器硬盘空间),更多可以使用的格式字符串请参考 streamlink STREAM
参数的文档。
第三个参数为可选参数,如果指定为 once
,那么当前直播的录像完成后脚本会自动退出,而不会继续监视后续直播。
录像的文件名格式为 openrec_{id}_YYMMDD_HHMMSS.ts
,其他与上面的相同。
另外,streamlink v0.14.2 对 OPENREC 的支持有问题,你需要参照这个 issue 手动加载更新后的 streamlink OPENREC 插件,或者等待 streamlink 本体发布新版本。如果运行中出现了 error: 'ascii' codec can't encode character
错误,那么你可能需要升级 Python 2.x 至 Python 3.x,或者在 streamlink/plugins/openrectv.py
文件的头部添加以下代码:
import sys
reload(sys)
sys.setdefaultencoding('utf8')
./record_twitch.sh twitch_id [format] [loop|once]
# Example
./record_twitch.sh kagura0mea 480p
./record_twitch.sh wuyikoei best once
第一个参数为 Twitch 用户名,就是直播页面 URL 中 twitch.tv
后面的那个。第二、第三个参数与 OPENREC 的脚本相同。
录像的文件名格式为 twitch_{id}_YYMMDD_HHMMSS.ts
,其他与上面的相同。
./record_twitcast.sh twitcasting_id [loop|once]
# Example
./record_twitcast.sh kaguramea
./record_twitcast.sh twitcasting_jp once
第一个参数为 TwitCasting 用户名,就是直播页面 URL 中 twitcasting.tv
后面的那个。第二个参数为可选参数,如果指定为 once
,那么当前直播的录像完成后脚本会自动退出,而不会继续监视后续直播。此脚本无法指定要抓取的直播流的画质。
录像的文件名格式为 twitcast_{id}_YYMMDD_HHMMSS.ts
,其他与上面的相同。
基本上 streamlink 支持的直播站点 都支持(包括国内的斗鱼、熊猫什么的)。
./record_streamlink.sh live_url [format] [loop|once]
# Example
./record_streamlink.sh "https://www.douyu.com/3614"
./record_streamlink.sh "https://www.panda.tv/371037"
第一个参数为直播间 URL,第二、第三个参数与 OPENREC 的脚本相同。
录像的文件名格式为 stream_YYMMDD_HHMMSS.ts
,其他与上面的相同。
此脚本适用于任何已知 .m3u8
地址的情况,不过只能对传入的该场直播进行录像,无法监视后续直播与自动录像。
如果上面的脚本没有适配某个平台(比如 Mirrativ、SHOWROOM),你也可以自己抓取出 .m3u8
地址手动开始录像。
./record_m3u8.sh "https://record.mirrativ.com/archive/hls/39/0018438274/playlist.m3u8"
第一个参数为 .m3u8
地址,录像的文件名格式为 stream_YYMMDD_HHMMSS.ts
。
第二个参数为可选参数,指定为 loop
可以让脚本每隔 30s 尝试下载该 .m3u8
地址。
这些脚本虽然是用来录像的,但是稍微修改一下也可以用于推流转播至其他直播平台。
将各脚本中的:
ffmpeg -i "$M3U8_URL" -codec copy -f mpegts "$FNAME" > "$FNAME.log" 2>&1
修改为:
RTMP_URL="这里填你的 RTMP 推流地址"
ffmpeg -i "$M3U8_URL" \
-codec copy -f mpegts "$FNAME" \ # 不需要录像的可以去掉这一行
-vcodec copy -acodec aac -strict -2 -f flv "$RTMP_URL" \
> "$FNAME.log" 2>&1
即可实现同时录像与转播推流。
如果用上面那些方式运行脚本,终端退出后脚本就会停止,所以你需要使用 nohup
命令将脚本放到后台中运行:
nohup ./record_youtube.sh "UCWCc8tO-uUl_7SJXIKJACMw" > mea.log &
这会把脚本的输出写入至日志文件 mea.log
(文件名自己修改),你可以随时使用 tail -f mea.log
命令查看实时日志。
其他脚本同理:
nohup ./record_twitch.sh kagura0mea > mea_twitch.log &
nohup ./record_twitcast.sh kaguramea > mea_twitcast.log &
nohup ./record_openrec.sh KaguraMea > mea_openrec.log &
使用命令 ps -ef | grep record
可以列出当前正在后台运行的录像脚本,其中第一个数字即为脚本进程的 PID:
root 1166 1 0 13:21 ? 00:00:00 /bin/bash ./record_youtube.sh ...
root 1558 1 0 13:25 ? 00:00:00 /bin/bash ./record_twitcast.sh ...
root 1751 1 0 13:27 ? 00:00:00 /bin/bash ./record_twitch.sh ...
root 1755 1 0 13:29 ? 00:00:00 /bin/bash ./record_openrec.sh ...
如果需要终止正在后台运行的脚本,可以使用命令 kill {pid}
(比如要终止上面的第一个 YouTube 录像脚本,运行 kill 1166
即可)。
YouTube 录像脚本中,ffmpeg 进程有时候在直播结束后还会继续运行,一直持续很长时间才自动退出(短则几十分钟,长则数小时,表现为日志文件不再更新或者不断出现 Last message repeated xxx times
),原因不明(正在尝试解决)。如果 ffmpeg 进程一直不退出就会造成阻塞,导致在这段时间内新开的直播无法录像,所以推荐在看到 YouTube 下播后手动终止一下可能挂起的 ffmpeg 进程。
首先运行 ps -ef | grep ffmpeg
获取 ffmpeg 进程的 PID:
root 26614 1919 0 18:23 pts/3 00:00:10 ffmpeg -i https://manifest.googlevideo.com/.../index.m3u8 -codec copy -f mpegts youtube_r0hNJe2pQ8s_20181028_182353.ts
然后使用 kill
命令终止 ffmpeg 进程:
kill 26614
MIT License (c) 2018 printempw