├── rcloneinclude.txt ├── config ├── korone.config └── global.config ├── streamrecorder.sh ├── autorun.sh ├── closescreen.sh ├── LICENSE ├── autobackup.sh ├── cleanlog.sh ├── README.md ├── backuper.sh ├── autoclean.sh ├── controller.sh └── recorder.sh /rcloneinclude.txt: -------------------------------------------------------------------------------- 1 | *.ts 2 | *.mp4 3 | *.txt 4 | *.jpg 5 | -------------------------------------------------------------------------------- /config/korone.config: -------------------------------------------------------------------------------- 1 | Interval=30 2 | LoopOrOnce=loop 3 | Backupmethod=rclone 4 | StreamOrRecord=record 5 | Youtube=UChAnqc_AY5_I3Px5dig3X1Q 6 | Bilibili=21421141 7 | -------------------------------------------------------------------------------- /config/global.config: -------------------------------------------------------------------------------- 1 | Backupmethod=rclone 2 | Servername=losangeles 3 | Rcloneremotename=magicalz 4 | Savefolder=recorded 5 | Logfolder=log 6 | Saveformat=ts 7 | Screenlogfolder=/var/log/screen 8 | Autobackup=on 9 | StreamOrRecord=record 10 | Twitchkey= 11 | Twitchpwd= 12 | Rtmpurl= 13 | -------------------------------------------------------------------------------- /streamrecorder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd `dirname $0` 3 | if [[ ! -n "$1" ]]; then 4 | echo "usage: $0 [start|restart|stop|cleanfile|cleanlog|backup]" 5 | exit 1 6 | fi 7 | if [ "$1" == "start" ] 8 | then 9 | ./autorun.sh 10 | elif [ "$1" == "stop" ] 11 | then 12 | ./closescreen.sh 13 | elif [ "$1" == "restart" ] 14 | then 15 | ./closescreen.sh all 16 | ./autorun.sh 17 | elif [ "$1" == "cleanfile" ] 18 | then 19 | ./autoclean.sh all 20 | elif [ "$1" == "cleanlog" ] 21 | then 22 | ./cleanlog.sh 23 | elif [ "$1" == "backup" ] 24 | then 25 | ./autobackup.sh all 26 | else 27 | echo "wrong parameter, please input parameter as bellow:" 28 | echo "usage: $0 [start|restart|stop|cleanfile|cleanlog|backup]" 29 | fi 30 | -------------------------------------------------------------------------------- /autorun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /etc/profile 3 | cd `dirname $0` 4 | LOG_PREFIX=$(date +"[%Y-%m-%d %H:%M:%S]") 5 | LOG_SUFFIX=$(date +"%Y%m%d_%H%M%S") 6 | for ((NUM=$(ls ./config|grep -v global|grep -c .config); NUM>0; --NUM)) 7 | do 8 | NAME=$(ls ./config|grep .config|grep -v global|sed 's/.config//g'|sed -n "$NUM"p) 9 | if [ -z "$(screen -ls|grep $NAME)" ] 10 | then 11 | sleep 1 12 | screen -L -t ${NAME}_${LOG_SUFFIX} -dmS $NAME ./controller.sh $NAME 13 | sleep 1 14 | echo "$LOG_PREFIX ===autorun=== running new screen for $NAME" 15 | echo "$LOG_PREFIX ===autorun=== check ./log/screen/screenlog_${NAME}_${LOG_SUFFIX}.log for detail" 16 | else 17 | echo "$LOG_PREFIX ===autorun=== skip...screen for $NAME already running" 18 | fi 19 | done 20 | -------------------------------------------------------------------------------- /closescreen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | LOG_PREFIX=$(date +"[%Y-%m-%d %H:%M:%S]") 3 | LOG_SUFFIX=$(date +"%Y%m%d_%H%M%S") 4 | if [ "$1" == "all" ] 5 | then 6 | screen -ls|awk '{line[NR]=$1}END{for(i=2;i<=NR-1;i++)print "screen -X -S "line[i]" quit"}'|sh 7 | echo "$LOG_PREFIX ===closescreen=== all screens have been closed" 8 | exit 0 9 | fi 10 | screen -ls 11 | echo "Please input the name of screen you want to close, input all to close all screens, input exit to exit:" 12 | read NAME 13 | [ "$NAME" == "exit" ]&&exit 0 14 | if [ "$NAME" == "all" ] 15 | then 16 | #LINECOUNT=$(screen -ls|wc -l) 17 | #screen -ls|awk -v line=$LINECOUNT -F '[ .]+' 'NR>=2&&NR<=line-2{print $1}'|awk '{print "screen -X -S "$0" quit"}'|sh 18 | screen -ls|awk '{line[NR]=$1}END{for(i=2;i<=NR-1;i++)print "screen -X -S "line[i]" quit"}'|sh 19 | echo "$LOG_PREFIX ===closescreen=== all screens have been closed" 20 | else 21 | echo "$LOG_PREFIX ===closescreen=== below screen will be closed:" 22 | screen -ls|grep $NAME 23 | screen -ls|grep $NAME|awk -F '[ .]+' '{print $1}'|awk '{print "screen -X -S "$0" quit"}'|sh 24 | fi 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 magicalz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /autobackup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #if [[ ! -n "$1" ]]; then 3 | #echo "usage: $0 [name|all] [youtube|bilibil|twitch|twitcast] [folderbydate] [filename]" 4 | #exit 1 5 | #fi 6 | [[ ! -d "log" ]]&&mkdir log 7 | LOG_PREFIX=$(date +"[%Y-%m-%d %H:%M:%S]") 8 | LOG_SUFFIX=$(date +"%Y%m%d_%H%M%S") 9 | NAME="${1:-all}" 10 | SITE="$2" 11 | BACKUPMETHOD=$(grep "Backupmethod" ./config/global.config|awk -F = '{print $2}') 12 | if [ "$NAME" != "all" ] && [ -f ./config/${NAME}.config ] && grep -q "Backupmethod" ./config/${NAME}.config 13 | then 14 | BACKUPMETHOD=$(grep "Backupmethod" ./config/${NAME}.config|awk -F = '{print $2}') 15 | fi 16 | [ "$BACKUPMETHOD" != "baidu" ] && [ "$BACKUPMETHOD" != "rclone" ] && [ "$BACKUPMETHOD" != "both" ] && echo "$LOG_PREFIX ===autobackup=== skip...please check config file, backupmethod should be baidu|rclone|both" && exit 1 17 | if [ "$NAME" == "all" ] 18 | then 19 | STREAMLINK_PROCESS=$(ps -efwww|grep streamlink|grep -v 'grep') 20 | FFMPEG_PROCESS=$(ps -efwww|grep ffmpeg|grep -v 'grep') 21 | else 22 | STREAMLINK_PROCESS=$(ps -efwww|grep streamlink|grep $NAME|grep -v 'grep') 23 | FFMPEG_PROCESS=$(ps -efwww|grep ffmpeg|grep $NAME|grep -v 'grep') 24 | fi 25 | if [ -z "$4" ] && [ -n "$STREAMLINK_PROCESS" ] || [ -n "$FFMPEG_PROCESS" ] 26 | then 27 | echo "$LOG_PREFIX ===autobackup=== skip...stream download in progress:" 28 | echo "$STREAMLINK_PROCESS" 29 | echo "$FFMPEG_PROCESS" 30 | exit 1 31 | fi 32 | echo "$LOG_PREFIX ===autobackup=== check ./log/screen/screenlog_autobackup_${LOG_SUFFIX}.log for detail" 33 | screen -L -t "autobackup_${LOG_SUFFIX}" -dmS "autobackup" ./backuper.sh $BACKUPMETHOD $NAME $SITE $3 $4 34 | -------------------------------------------------------------------------------- /cleanlog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SAVEFOLDERGLOBAL=$(grep "Savefolder" ./config/global.config|awk -F = '{print $2}') 4 | LOGFOLDERGLOBAL=$(grep "Logfolder" ./config/global.config|awk -F = '{print $2}') 5 | SCREENLOGFOLDER=$(grep "Screenlogfolder" ./config/global.config|awk -F = '{print $2}') 6 | LOG_PREFIX=$(date +"[%Y-%m-%d %H:%M:%S]") 7 | LOG_SUFFIX=$(date +"%Y%m%d_%H%M%S") 8 | 9 | find ./$SAVEFOLDERGLOBAL/ -maxdepth 4 \( -name "*.ts" -o -name "*.mp4" -o -name "*.info.txt" -o -name "*.jpg" \) -type f -mmin +720 -exec ls -l {} \; > "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 10 | find ./$SAVEFOLDERGLOBAL/ -maxdepth 4 \( -name "*.ts" -o -name "*.mp4" -o -name "*.info.txt" -o -name "*.jpg" \) -type f -mmin +720 -delete >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 11 | find ./$SAVEFOLDERGLOBAL/ -maxdepth 4 -name "*.ts.*" -type f -mmin +720 -exec ls -l {} \; >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 12 | find ./$SAVEFOLDERGLOBAL/ -maxdepth 4 -name "*.ts.*" -type f -mmin +720 -delete >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 13 | find ./$SAVEFOLDERGLOBAL/ -mindepth 3 -maxdepth 3 -name "[0-9]*" -type d -empty -mmin +720 >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 14 | find ./$SAVEFOLDERGLOBAL/ -mindepth 3 -maxdepth 3 -name "[0-9]*" -type d -empty -mmin +720 -exec rm -rf {} \; >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 15 | find ./$LOGFOLDERGLOBAL/ -maxdepth 3 -name "*.log" -type f -mmin +1440 -exec ls -l {} \; >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 16 | find ./$LOGFOLDERGLOBAL/ -maxdepth 3 -name "*.log" -type f -mmin +1440 -delete >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 17 | find $SCREENLOGFOLDER -name "*.log" -type f -mmin +1440 -exec ls -l {} \; >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 18 | find $SCREENLOGFOLDER -name "*.log" -type f -mmin +1440 -delete >> "./log/cleanlog_$LOG_SUFFIX.log" 2>&1 19 | echo "$LOG_PREFIX ===cleanlog=== check ./log/cleanlog_$LOG_SUFFIX.log for detail" 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stream Recorder 2 | 这是一个视频直播的推流/录制工具,支持youtube/twitch/twitcasting/bilibili等主流直播平台 3 | 本项目源于[live-stream-recorder](https://github.com/printempw/live-stream-recorder),在此基础上进行了大量魔改,主要是增加了自动运行、自动备份、自动清理等功能,以及使用配置文件大幅简化了使用方法,可以做到无人值守的自动推流与录制 4 | 5 | ### 如何配置本工具 6 | 7 | 可以参考我之前写的一篇B站专栏:https://www.bilibili.com/read/cv3697584 8 | 9 | + 程序依赖 10 | 本工具依赖于以下程序,请自行安装并保证能在 $PATH 中找到。 11 | + ffmpeg 12 | + youtube-dl 13 | + streamlink 14 | + you-get 15 | + screen 16 | + ~~BaiduPCS-Go 该项目已经消失在历史的长河里~~ 17 | + Rclone 18 | 19 | + 配置文件 20 | + global.config 21 | 全局配置文件,用于配置推流地址,视频保存目录等 22 | 具体参数说明: 23 | 24 | > StreamOrRecord 25 | 可选: stream/record/both,此参数决定是推流还是录制,或者二者兼顾 26 | > Savefolder 27 | 此参数是视频录制保存的根目录 28 | > Logfolder 29 | Log文件保存的目录 30 | > Screenlogfolder 31 | Screen Log文件保存的目录,和/etc/screenrc里的screen log路径一致,也可以设置成和Logfolder一样的值 32 | > Autobackup 33 | 可选: on/off,此参数是自动备份开关,选择on则视频录制后会自动备份到指定网盘并删除本地文件 34 | > Backupmethod 35 | 可选: rclone/baidu/both,此参数决定备份方式,可以是rclone或者BaiduPCS-Go,备份到onedrive或者度盘 36 | > Saveformat 37 | 可选: ts/mp4,此参数是视频录制的文件格式 38 | > Rcloneremotename 39 | 此参数是rclone的remote name,在配置rclone的时候remote name相当于网盘的别名 40 | > Servername 41 | 此参数是rclone备份时上传到网盘的目录名称,多个服务器同时运行本工具,需要以不同的服务器名字作为区分 42 | > Rtmpurl 43 | 此参数是推流地址,如rtmp://live.mobcrush.net/stream/115ed1677062e51c7339ebe7f1142a0f66db42cb86a5d27 44 | > Twitchkey 45 | 此参数是Twitch平台的api key,可以在Twitch官网申请,用于Twitch开播检测,如果不监控Twitch频道则可以忽略 46 | > Twitchpwd 47 | 此参数是Twitch平台的api key对应的password,可以在Twitch官网申请,用于Twitch开播检测,如果不监控Twitch频道则可以忽略 48 | 49 | + name.config 50 | 频道配置文件,用于配置单个频道的具体地址以及推流和备份方式等,可以建立多个 51 | 具体参数说明: 52 | > Interval 53 | 此参数是开播检测的时间间隔,默认30,即30秒 54 | > LoopOrOnce 55 | 可选: loop/once,此参数决定程序是一直运行还是单次运行 56 | > Backupmethod 57 | 同global.config,如果在此设置则会覆盖global.config里的值,用于单独设置某个频道的备份方式 58 | > StreamOrRecord 59 | 同global.config,如果在此设置则会覆盖global.config里的值,用于单独设置某个频道是推流还是录制 60 | > Rtmpurl 61 | 同global.config,如果在此设置则会覆盖global.config里的值,用于单独设置某个频道的推流地址 62 | > Youtube 63 | youtube频道的地址,需要注意的是只需要填写频道ID,如UC1opHUrw8rvnsadT-iGp7Cg 64 | > Bilibili 65 | bilibili频道的地址,只需要填写频道ID,如14917277 66 | > Twitch 67 | twitch频道的地址,只需要填写频道ID,如rin_co_co 68 | > Twitcast 69 | twitcasting频道的地址,只需要填写频道ID,如c:rin_co 70 | 71 | ### 如何运行本工具 72 | ./streamrecorder.sh [start|restart|stop|cleanfile|cleanlog|backup], 程序总入口,用于统一调用其他脚本 73 | 以下脚本均可通过streamrecorder.sh来运行 74 | ./autorun.sh,程序启动脚本,只需运行一次,会自动遍历配置文件夹里的各个频道并开始推流和录制,每个频道会新建一个screen进程方便随时监控 75 | ./autobackup.sh,备份脚本,如果在全局设置里设置为on,则视频录制以后会自动上传到指定网盘并删除本地文件,也可以手动运行 76 | ./autoclean.sh,清理脚本,每次备份后会自动调用,也可以手动运行 77 | ./closescreen.sh,手动运行,运行后会列出当前活动的screen子进程,输入screen名称关闭指定子进程或者输入all关闭所有子进程 78 | ./cleanlog.sh,手动运行,用于清理24小时以上的日志文件和空白文件 79 | 80 | ### screen log的保存目录 81 | screen log是程序运行时screen输出的日志文件,编辑/etc/screenrc,添加以下内容 82 | logfile /var/log/screen/screenlog_%t.log 83 | 新建screen log目录 84 | mkdir /var/log/screen 85 | chmod 777 /var/log/screen 86 | 在程序的log目录下建立screen log目录的软链接 87 | ln -s /var/log/screen /home/recorder/StreamRecorder/log/screen 88 | 89 | ### Twitcasting频道的录制 90 | ~~Twitcasting需要livedl的支持,下载并放到StreamRecorder根目录即可~~ 91 | ~~wget https://github.com/yayugu/livedl/releases/download/20181215.36/livedl~~ 92 | ~~chmod +x livedl~~ 93 | 现已统一使用streamlink录制视频,不需要另外下载livedl 94 | ### 开机自启 95 | vi /etc/rc.local 96 | 添加以下内容,recorder是运行程序的用户名,如果不指定则默认以root用户运行 97 | su - recorder -c "/home/recorder/StreamRecorder/streamrecorder.sh start 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /backuper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #usage: $0 [backupmethod] [name|all] [youtube|bilibili|twitch|twitcast] [folderbydate] [filename] 3 | 4 | BACKUPMETHOD="${1:-rclone}" 5 | NAME="${2:-all}" 6 | SITE="$3" 7 | FOLDERBYDATE="$4" 8 | FILENAME="$5" 9 | SERVERNAME=$(grep "Servername" ./config/global.config|awk -F = '{print $2}') 10 | SAVEFOLDER=$(grep "Savefolder" ./config/global.config|awk -F = '{print $2}') 11 | REMOTENAME=$(grep "Rcloneremotename" ./config/global.config|awk -F = '{print $2}') 12 | LOG_PREFIX=$(date +"[%Y-%m-%d %H:%M:%S]") 13 | LOG_SUFFIX=$(date +"%Y%m%d_%H%M%S") 14 | if [ "$BACKUPMETHOD" == "baidu" ] || [ "$BACKUPMETHOD" == "both" ] 15 | then 16 | TARGETPATH="/StreamRecorder/$SERVERNAME" 17 | [ "$NAME" != "all" ] && TARGETPATH="$TARGETPATH/$SAVEFOLDER" && SAVEFOLDER="$SAVEFOLDER/$NAME" 18 | [ -n "$SITE" ] && TARGETPATH="$TARGETPATH/$NAME" && SAVEFOLDER="$SAVEFOLDER/$SITE" 19 | [ -n "$FOLDERBYDATE" ] && TARGETPATH="$TARGETPATH/$SITE" && SAVEFOLDER="$SAVEFOLDER/$FOLDERBYDATE" 20 | [ -n "$FILENAME" ] && FILENAME=$(echo "$FILENAME"|awk -F . '{print $1}') && TARGETPATH="$TARGETPATH/$FOLDERBYDATE" && SAVEFOLDER="$SAVEFOLDER/$FILENAME.*" 21 | echo "$LOG_PREFIX ===baidubackup=== BaiduPCS begin to backup files" 22 | echo "$LOG_PREFIX ===baidubackup=== check ./log/BaiduPCS_${LOG_SUFFIX}.log for detail" 23 | BaiduPCS-Go upload "$SAVEFOLDER" "$TARGETPATH" > "./log/BaiduPCS_${LOG_SUFFIX}.log" 2>&1 24 | fi 25 | if [ "$BACKUPMETHOD" == "rclone" ] || [ "$BACKUPMETHOD" == "both" ] 26 | then 27 | TARGETPATH="${REMOTENAME}:StreamRecorder/${SERVERNAME}/${SAVEFOLDER}" 28 | [ "$NAME" != "all" ] && SAVEFOLDER="$SAVEFOLDER/$NAME" && TARGETPATH="$TARGETPATH/$NAME" 29 | [ -n "$SITE" ] && SAVEFOLDER="$SAVEFOLDER/$SITE" && TARGETPATH="$TARGETPATH/$SITE" 30 | [ -n "$FOLDERBYDATE" ] && SAVEFOLDER="$SAVEFOLDER/$FOLDERBYDATE" && TARGETPATH="$TARGETPATH/$FOLDERBYDATE" 31 | echo "$LOG_PREFIX ===rclonebackup=== rclone begin to backup files" 32 | echo "$LOG_PREFIX ===rclonebackup=== check ./log/rclone_${LOG_SUFFIX}.log for detail" 33 | if [ -n "$FILENAME" ] 34 | then 35 | FILENAME=$(echo "$FILENAME"|awk -F . '{print $1}') 36 | rclone copy --no-traverse "$SAVEFOLDER" "$TARGETPATH" --include "$FILENAME.*" --buffer-size 32M --transfers 6 --low-level-retries 200 -v > "./log/rclone_${LOG_SUFFIX}.log" 2>&1 37 | else 38 | rclone copy --no-traverse "$SAVEFOLDER" "$TARGETPATH" --include-from rcloneinclude.txt --buffer-size 32M --transfers 6 --low-level-retries 200 -v > "./log/rclone_${LOG_SUFFIX}.log" 2>&1 39 | fi 40 | fi 41 | 42 | [ "$BACKUPMETHOD" == "baidu" ] || [ "$BACKUPMETHOD" == "both" ] && ! grep -q -E "上传文件失败|全部上传完毕, 总大小: 0B" ./log/BaiduPCS_${LOG_SUFFIX}.log && BAIDUSUCCESS="SUCCESS" 43 | [ "$BACKUPMETHOD" == "rclone" ] || [ "$BACKUPMETHOD" == "both" ] && ! grep -q "error" ./log/rclone_${LOG_SUFFIX}.log && grep -q "Copied (new)" ./log/rclone_${LOG_SUFFIX}.log && RCLONESUCCESS="SUCCESS" 44 | if ([ "$BACKUPMETHOD" == "baidu" ] && [ "$BAIDUSUCCESS" == "SUCCESS" ]) || ([ "$BACKUPMETHOD" == "rclone" ] && [ "$RCLONESUCCESS" == "SUCCESS" ]) || ([ "$BACKUPMETHOD" == "both" ] && [ "$BAIDUSUCCESS" == "SUCCESS" ] && [ "$RCLONESUCCESS" == "SUCCESS" ]) 45 | then 46 | echo "$LOG_PREFIX ===backup=== backup complete, begin to clean files" 47 | ./autoclean.sh $NAME $SITE $FOLDERBYDATE $FILENAME 48 | else 49 | [ "$BACKUPMETHOD" == "baidu" ] || [ "$BACKUPMETHOD" == "both" ] && [ "$BAIDUSUCCESS" != "SUCCESS" ] && echo "$LOG_PREFIX ===baidubackup=== skip clean...BaiduPCS backup failed, check ./log/BaiduPCS_${LOG_SUFFIX}.log for detail" 50 | [ "$BACKUPMETHOD" == "rclone" ] || [ "$BACKUPMETHOD" == "both" ] && [ "$RCLONESUCCESS" != "SUCCESS" ] && echo "$LOG_PREFIX ===rclonebackup=== skip clean...rclone backup failed, check ./log/rclone_${LOG_SUFFIX}.log for detail" 51 | fi 52 | 53 | -------------------------------------------------------------------------------- /autoclean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z "$1" ] 3 | then 4 | echo "usage: $0 [all|name] [youtube|bilibili|twitch|twitcast] [folderbydate] [filename]" 5 | exit 1 6 | fi 7 | if [ "$1" == "all" ] && [ -n "$2" ] 8 | then 9 | echo "wrong parameter, only accept all or [name] [site] [date] [filename]" 10 | echo "usage: $0 [all|name] [youtube|bilibili|twitch|twitcast] [folderbydate] [filename]" 11 | exit 1 12 | fi 13 | NAME="${1:-all}" 14 | SITE="$2" 15 | SAVEFOLDER=$(grep "Savefolder" ./config/global.config|awk -F = '{print $2}') 16 | LOG_PREFIX=$(date +"[%Y-%m-%d %H:%M:%S]") 17 | LOG_SUFFIX=$(date +"%Y%m%d_%H%M%S") 18 | echo "$LOG_PREFIX ===autoclean=== check ./log/clean_$LOG_SUFFIX.log for detail" 19 | [ "$NAME" != "all" ] && SAVEFOLDER="${SAVEFOLDER}/${NAME}" 20 | [ -n "$SITE" ] && SAVEFOLDER="${SAVEFOLDER}/${SITE}" 21 | [ -n "$3" ] && SAVEFOLDER="${SAVEFOLDER}/${3}" 22 | if [ -n "$4" ] 23 | then 24 | FILENAME=$(echo "$4"|awk -F . '{print $1}') 25 | echo "$LOG_PREFIX below files will be deleted:" >> "./log/clean_${LOG_SUFFIX}.log" 26 | find $SAVEFOLDER -maxdepth 4 -name "*.*" -size 0 -type f -exec ls -l {} \; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 27 | find $SAVEFOLDER -maxdepth 4 -name "*.*" -size 0 -type f -delete ; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 28 | find $SAVEFOLDER -maxdepth 4 -name "${FILENAME}.*" -type f -exec ls -l {} \; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 29 | find $SAVEFOLDER -maxdepth 4 -name "${FILENAME}.*" -type f -delete ; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 30 | exit 0 31 | fi 32 | if [ "$NAME" == "all" ] 33 | then 34 | STREAMLINK_PROCESS=$(ps -efwww|grep streamlink|grep -v 'grep') 35 | FFMPEG_PROCESS=$(ps -efwww|grep ffmpeg|grep -v 'grep') 36 | BAIDUPCS_PROCESS=$(ps -ef|grep 'BaiduPCS-Go upload'|grep -v 'grep') 37 | RCLONE_PROCESS=$(ps -ef|grep 'rclone copy'|grep -v 'grep') 38 | else 39 | STREAMLINK_PROCESS=$(ps -efwww|grep streamlink|grep $NAME|grep -v 'grep') 40 | FFMPEG_PROCESS=$(ps -efwww|grep ffmpeg|grep $NAME|grep -v 'grep') 41 | BAIDUPCS_PROCESS=$(ps -ef|grep 'BaiduPCS-Go upload'|grep $NAME|grep -v 'grep') 42 | RCLONE_PROCESS=$(ps -ef|grep 'rclone copy'|grep $NAME|grep -v 'grep') 43 | fi 44 | #check if download or upload is running 45 | if [ -z "$STREAMLINK_PROCESS" ] && [ -z "$FFMPEG_PROCESS" ] && [ -z "$BAIDUPCS_PROCESS" ] && [ -z "$RCLONE_PROCESS" ] 46 | then 47 | echo "$LOG_PREFIX below files will be deleted:" >> "./log/clean_${LOG_SUFFIX}.log" 48 | find $SAVEFOLDER -maxdepth 4 -name "*.*" -size 0 -type f -exec ls -l {} \; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 49 | find $SAVEFOLDER -maxdepth 4 -name "*.*" -size 0 -type f -delete ; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 50 | find $SAVEFOLDER -maxdepth 4 \( -name "*.ts" -o -name "*.mp4" -o -name "*.info.txt" -o -name "*.jpg" \) -type f -exec ls -l {} \; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 51 | find $SAVEFOLDER -maxdepth 4 \( -name "*.ts" -o -name "*.mp4" -o -name "*.info.txt" -o -name "*.jpg" \) -type f -delete ; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 52 | if [ -d ~/.cache/rclone ]; then 53 | find ~/.cache/rclone -maxdepth 9 -name "*.*" -type f -exec ls -l {} \; >> "./log/clean_${LOG_SUFFIX}.log" 2>&1 54 | rm -rf ~/.cache/rclone 55 | fi 56 | elif [ -n "$STREAMLINK_PROCESS" ] || [ -n "$FFMPEG_PROCESS" ] 57 | then 58 | echo "$LOG_PREFIX skip...stream download is in progress:" >> "./log/clean_${LOG_SUFFIX}.log" 59 | echo "$STREAMLINK_PROCESS" >> "./log/clean_${LOG_SUFFIX}.log" 60 | echo "$FFMPEG_PROCESS" >> "./log/clean_${LOG_SUFFIX}.log" 61 | elif [ -n "$BAIDUPCS_PROCESS" ] || [ -n "$RCLONE_PROCESS" ] 62 | then 63 | echo "$LOG_PREFIX skip...stream upload is in progress:" >> "./log/clean_${LOG_SUFFIX}.log" 64 | echo "$BAIDUPCS_PROCESS" >> "./log/clean_${LOG_SUFFIX}.log" 65 | echo "$RCLONE_PROCESS" >> "./log/clean_${LOG_SUFFIX}.log" 66 | fi 67 | -------------------------------------------------------------------------------- /controller.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ ! -n "$1" ]] 4 | then 5 | echo "usage: $0 [name] [format]" 6 | exit 1 7 | fi 8 | 9 | if [ ! -f ./config/${1}.config ] 10 | then 11 | echo "===controller=== skip...$1 config file does not exist" 12 | exit 1 13 | fi 14 | 15 | FORMAT="${2:-best}" 16 | SAVEFOLDERGLOBAL=$(grep "Savefolder" ./config/global.config|awk -F = '{print $2}') 17 | LOGFOLDERGLOBAL=$(grep "Logfolder" ./config/global.config|awk -F = '{print $2}') 18 | SAVEFOLDER="$SAVEFOLDERGLOBAL/$1/" 19 | LOGFOLDER="$LOGFOLDERGLOBAL/$1/" 20 | #SAVEFOLDER=$(grep "Savefolder" ./config/"$1".config|awk -F = '{print $2}') 21 | #LOGFOLDER=$(grep "Logfolder" ./config/"$1".config|awk -F = '{print $2}') 22 | INTERVAL=$(grep "Interval" ./config/"$1".config|awk -F = '{print $2}') 23 | LOOP=$(grep "LoopOrOnce" ./config/"$1".config|awk -F = '{print $2}') 24 | YOUTUBE=$(grep "Youtube" ./config/"$1".config|awk -F = '{print $2}') 25 | BILIBILI=$(grep "Bilibili" ./config/"$1".config|awk -F = '{print $2}') 26 | TWITCH=$(grep "Twitch" ./config/"$1".config|awk -F = '{print $2}') 27 | TWITCAST=$(grep "Twitcast" ./config/"$1".config|awk -F = '{print $2}') 28 | STREAMORRECORD=$(grep "StreamOrRecord" ./config/global.config|awk -F = '{print $2}') 29 | if grep -q "StreamOrRecord" ./config/${1}.config 30 | then 31 | STREAMORRECORD=$(grep "StreamOrRecord" ./config/${1}.config|awk -F = '{print $2}') 32 | fi 33 | RTMPURL=$(grep "Rtmpurl" ./config/global.config|awk -F = '{print $2}') 34 | if grep -q "Rtmpurl" ./config/${1}.config 35 | then 36 | RTMPURL=$(grep "Rtmpurl" ./config/${1}.config|awk -F = '{print $2}') 37 | fi 38 | 39 | [ "$STREAMORRECORD" != "both" ] && [ "$STREAMORRECORD" != "record" ] && [ "$STREAMORRECORD" != "stream" ] && echo "===controller=== skip...please check StreamOrRecord parameter in config file, should be record|stream|both" && exit 1 40 | [ "$STREAMORRECORD" == "both" ] || [ "$STREAMORRECORD" == "stream" ] && [ -z "$RTMPURL" ] && echo "===controller=== skip...StreamOrRecord is \"$STREAMORRECORD\" but Rtmpurl is empty, please check StreamOrRecord and Rtmpurl parameters in config file" && exit 1 41 | 42 | [[ ! -d "${SAVEFOLDERGLOBAL}" ]]&&mkdir ${SAVEFOLDERGLOBAL} 43 | [[ ! -d "${LOGFOLDERGLOBAL}" ]]&&mkdir ${LOGFOLDERGLOBAL} 44 | [[ ! -d "${SAVEFOLDER}" ]]&&mkdir ${SAVEFOLDER} 45 | [[ ! -d "${LOGFOLDER}" ]]&&mkdir ${LOGFOLDER} 46 | 47 | #youtube 48 | 49 | if [[ -n "$YOUTUBE" ]]; then 50 | [[ ! -d "${SAVEFOLDER}youtube" ]]&&mkdir ${SAVEFOLDER}youtube 51 | #[[ ! -d "${SAVEFOLDER}youtube/metadata" ]]&&mkdir ${SAVEFOLDER}youtube/metadata 52 | [[ ! -d "${LOGFOLDER}youtube" ]]&&mkdir ${LOGFOLDER}youtube 53 | sleep 5 54 | ./recorder.sh youtube $YOUTUBE $1 ${SAVEFOLDER}youtube/ ${LOGFOLDER}youtube/ $FORMAT $LOOP $INTERVAL $STREAMORRECORD $RTMPURL & 55 | sleep 10 56 | fi 57 | 58 | #bil 59 | if [[ -n "$BILIBILI" ]]; then 60 | [[ ! -d "${SAVEFOLDER}bilibili" ]]&&mkdir ${SAVEFOLDER}bilibili 61 | [[ ! -d "${SAVEFOLDER}bilibili/metadata" ]]&&mkdir ${SAVEFOLDER}bilibili/metadata 62 | [[ ! -d "${LOGFOLDER}bilibili" ]]&&mkdir ${LOGFOLDER}bilibili 63 | sleep 5 64 | ./recorder.sh bilibili $BILIBILI $1 ${SAVEFOLDER}bilibili/ ${LOGFOLDER}bilibili/ $FORMAT $LOOP $INTERVAL $STREAMORRECORD $RTMPURL & 65 | sleep 10 66 | fi 67 | 68 | #twitch twitch_id [format] [loop|once] [interval] [savefolder] 69 | if [[ -n "$TWITCH" ]]; then 70 | [[ ! -d "${SAVEFOLDER}twitch" ]]&&mkdir ${SAVEFOLDER}twitch 71 | [[ ! -d "${SAVEFOLDER}twitch/metadata" ]]&&mkdir ${SAVEFOLDER}twitch/metadata 72 | [[ ! -d "${LOGFOLDER}twitch" ]]&&mkdir ${LOGFOLDER}twitch 73 | sleep 5 74 | ./recorder.sh twitch $TWITCH $1 ${SAVEFOLDER}twitch/ ${LOGFOLDER}twitch/ $FORMAT $LOOP $INTERVAL $STREAMORRECORD $RTMPURL & 75 | sleep 10 76 | fi 77 | #TWITCAST 78 | if [[ -n "$TWITCAST" ]]; then 79 | [[ ! -d "${SAVEFOLDER}twitcast" ]]&&mkdir ${SAVEFOLDER}twitcast 80 | [[ ! -d "${SAVEFOLDER}twitcast/metadata" ]]&&mkdir ${SAVEFOLDER}twitcast/metadata 81 | [[ ! -d "${LOGFOLDER}twitcast" ]]&&mkdir ${LOGFOLDER}twitcast 82 | #sleep 5 83 | #[[ ! -f "${SAVEFOLDER}twitcast/livedl" ]]&&ln ./livedl ${SAVEFOLDER}twitcast/ 84 | sleep 5 85 | ./recorder.sh twitcast $TWITCAST $1 ${SAVEFOLDER}twitcast/ ${LOGFOLDER}twitcast/ $FORMAT $LOOP $INTERVAL $STREAMORRECORD $RTMPURL & 86 | sleep 10 87 | fi 88 | #OPENREC 89 | #./record_openrec.sh $OPENRCE $FORAMT $LOOP $INTERVAL ${SAVEFOLDER}& 90 | 91 | wait 92 | -------------------------------------------------------------------------------- /recorder.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Stream Recorder 3 | 4 | if [ -z "$1" ] || [ -z "$2" ]; then 5 | echo "usage: $0 site channel_id [name] [savefolder] [logfolder] [format] [loop|once] [interval] [streamorrecord] [rtmpurl]" 6 | exit 1 7 | fi 8 | 9 | 10 | # Set the default value of parameters 11 | SITE="${1:-youtube}" 12 | CHANNELID="$2" 13 | NAME="$3" 14 | SAVEFOLDER="$4" 15 | LOGFOLDER="$5" 16 | FORMAT="${6:-best}" 17 | LOOPORONCE="${7:-once}" 18 | INTERVAL="${8:-30}" 19 | STREAMORRECORD="${9:-record}" 20 | RTMPURL="${10}" 21 | AUTOBACKUP=$(grep "Autobackup" ./config/global.config|awk -F = '{print $2}') 22 | SAVEFORMAT=$(grep "Saveformat" ./config/global.config|awk -F = '{print $2}') 23 | 24 | # Construct full URL if only channel id given 25 | [ "$SITE" == "youtube" ] && LIVE_URL="https://www.youtube.com/channel/$CHANNELID/live" 26 | [ "$SITE" == "bilibili" ] && LIVE_URL="https://live.bilibili.com/$CHANNELID" 27 | [ "$SITE" == "twitch" ] && LIVE_URL="https://www.twitch.tv/$CHANNELID" 28 | [ "$SITE" == "twitcast" ] && LIVE_URL="https://twitcasting.tv/$CHANNELID" 29 | 30 | while true; do 31 | # Monitor live streams of specific channel 32 | while true; do 33 | LOG_PREFIX="$(date +'[%Y-%m-%d %H:%M:%S]') ===$SITE===" 34 | echo "$LOG_PREFIX Checking $LIVE_URL..." 35 | echo "$LOG_PREFIX Try to get current live stream of $LIVE_URL" 36 | 37 | #Check whether the channel is live 38 | #curl -s -N https://www.youtube.com/channel/$1/live|grep -q '\\"isLive\\":true' && break 39 | #wget -q -O- $LIVE_URL|grep -q '\\"isLive\\":true' && break 40 | [ "$SITE" == "youtube" ] && wget -q -O- "$LIVE_URL"|grep 'www.youtube.com/embed/live_stream'|grep -q '\"isLive\":true' && break 41 | if [ "$SITE" == "bilibili" ] 42 | then 43 | YOUTUBEURL=$(grep "Youtube" ./config/"$NAME".config|awk -F = '{print $2}') 44 | if [ -n "$YOUTUBEURL" ] && wget -q -O- "https://www.youtube.com/channel/$YOUTUBEURL/live" |grep 'www.youtube.com/embed/live_stream'|grep -q '\"isLive\":true' 45 | then 46 | echo "$LOG_PREFIX skip...youtube channel is already streaming!" 47 | else 48 | wget -q -O- "https://api.live.bilibili.com/room/v1/Room/get_info?room_id=$CHANNELID&from=room"|grep -q '\"live_status\"\:1' && break 49 | fi 50 | fi 51 | if [ "$SITE" == "twitch" ] 52 | then 53 | TWITCHKEY=$(grep "Twitchkey" ./config/global.config|awk -F = '{print $2}') 54 | TWITCHPWD=$(grep "Twitchpwd" ./config/global.config|awk -F = '{print $2}') 55 | if [ -z "$TWITCHKEY" ] || [ -z "$TWITCHPWD" ] 56 | then 57 | echo "$LOG_PREFIX skip...Twitchkey or Twitchpwd is empty!" 58 | else 59 | #wget -q -O- --header="Client-ID: $TWITCHKEY" https://api.twitch.tv/helix/streams?user_login=$CHANNELID|grep -q \"type\":\"live\" && break 60 | TWITCHTOKEN=$(curl -X POST 'https://id.twitch.tv/oauth2/token?client_id='$TWITCHKEY'&client_secret='$TWITCHPWD'&grant_type=client_credentials' | awk -F '[,:"]+' '{for(i=1;i<=NF-1;i++)if($i ~ /access_token/)print $(i+1)}') 61 | wget -q -O- --header="Client-ID: $TWITCHKEY" --header="Authorization: Bearer ${TWITCHTOKEN}" https://api.twitch.tv/helix/streams?user_login=$CHANNELID | grep -q \"type\":\"live\" && break 62 | fi 63 | fi 64 | if [ "$SITE"="twitcast" ] 65 | then 66 | wget -q -O- "https://twitcasting.tv/streamserver.php?target=$CHANNELID&mode=client" | grep -q '"live":true' && break 67 | fi 68 | echo "$LOG_PREFIX The stream is not available now." 69 | echo "$LOG_PREFIX Retry after $INTERVAL seconds..." 70 | sleep $INTERVAL 71 | done 72 | #Create save folder by date 73 | FOLDERBYDATE="$(date +"%Y%m%d")" 74 | [[ ! -d "${SAVEFOLDER}${FOLDERBYDATE}" ]]&&mkdir ${SAVEFOLDER}${FOLDERBYDATE} 75 | #[[ ! -d "${SAVEFOLDER}${FOLDERBYDATE}/metadata" ]]&&mkdir ${SAVEFOLDER}${FOLDERBYDATE}/metadata 76 | 77 | #Fetch live information 78 | if [ "$SITE" == "youtube" ] 79 | then 80 | METADATA=$(youtube-dl --get-id --get-title --get-thumbnail --get-description \ 81 | --no-check-certificate --no-playlist --playlist-items 1 \ 82 | "${LIVE_URL}" 2>/dev/null) 83 | [ -z "$METADATA" ] && echo "$LOG_PREFIX skip...youtube metadata is empty!" && continue 84 | # Extract stream title 85 | #Title=$(echo "$METADATA" | sed -n '1p'|sed 's#[()/\\!-\$]##g') 86 | # Extract video id of live stream 87 | ID=$(echo "$METADATA" | sed -n '2p') 88 | # Extract stream cover url 89 | #COVERURL=$(echo "$METADATA" | sed -n '3p') 90 | COVERURL="https://i.ytimg.com/vi/${ID}/maxresdefault.jpg" 91 | #FNAME="youtube_${Title}_$(date +"%Y%m%d_%H%M%S")_${ID}.${SAVEFORMAT}" 92 | FNAME="youtube_$(date +"%Y%m%d_%H%M%S")_${ID}.${SAVEFORMAT}" 93 | # Also save the metadata and cover to file 94 | if [ "$STREAMORRECORD" != "stream" ]; then 95 | echo "$METADATA" > "${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}.info.txt" 96 | wget -O "${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}.jpg" "$COVERURL" 97 | fi 98 | fi 99 | if [ "$SITE" == "bilibili" ] 100 | then 101 | # Savetitle 102 | TITLE=$(you-get -i "$LIVE_URL"|sed -n '2p'|cut -c 22-|cut -d '.' -f 1|sed 's/[()/\\!-\$]//g') 103 | # Record using MPEG-2 TS format to avoid broken file caused by interruption 104 | FNAME="bil_${CHANNELID}_${TITLE}_$(date +"%Y%m%d_%H%M%S").${SAVEFORMAT}" 105 | fi 106 | if [ "$SITE" == "twitch" ] 107 | then 108 | METADATA=$(youtube-dl --get-id --get-title --get-description "$LIVE_URL") 109 | #TITLE=$(echo "$METADATA" | sed -n '3p'|sed 's/[()/\\!-\$]//g') 110 | ID=$(echo "$METADATA" | sed -n '2p') 111 | #FNAME="twitch_${ID}_${TITLE}_$(date +"%Y%m%d_%H%M%S").${SAVEFORMAT}" 112 | FNAME="twitch_$(date +"%Y%m%d_%H%M%S")_${ID}.${SAVEFORMAT}" 113 | [ "$STREAMORRECORD" != "stream" ] && echo "$METADATA" > "${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}.info.txt" 114 | fi 115 | if [ "$SITE" == "twitcast" ] 116 | then 117 | #MOVIEID=$(wget -q -O- ${LIVE_URL} | grep data-movie-id | awk -F '[=\"]+' '{for(i=1;i<=NF-1;i++)if($i ~ /data-movie-id/)print $(i+1)}') 118 | #ID=$(echo "$CHANNELID"|sed 's/:/:/') 119 | #LIVEDL_FNAME="${ID}_${MOVIEID}.${SAVEFORMAT}" 120 | FNAME="twitcast_$(date +"%Y%m%d_%H%M%S")_${CHANNELID}.${SAVEFORMAT}" 121 | fi 122 | # Print logs 123 | echo "$LOG_PREFIX Start recording, stream saved to ${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}" 124 | [ "$SITE" == "youtube" ] || [ "$SITE" == "twitch" ] && echo "$LOG_PREFIX metadata saved to ${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}.info.txt" 125 | [ "$SITE" == "youtube" ] && echo "$LOG_PREFIX cover saved to ${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}.jpg" 126 | echo "$LOG_PREFIX recording log saved to ${LOGFOLDER}${FNAME}.log, streaming log saved to ${LOGFOLDER}${FNAME}.streaming.log" 127 | # Record using MPEG-2 TS format to avoid broken file caused by interruption 128 | # Start recording 129 | # ffmpeg -i "$M3U8_URL" -codec copy -f mpegts "savevideo/$FNAME" > "savevideo/$FNAME.log" 2>&1 130 | # Use streamlink "--hls-live-restart" parameter to record for HLS seeking support 131 | #M3U8_URL=$(streamlink --stream-url "https://www.youtube.com/watch?v=${ID}" "best") 132 | #ffmpeg -i "$M3U8_URL" -codec copy -f hls -hls_time 3600 -hls_list_size 0 "${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}" > "${LOGFOLDER}${FNAME}.log" 2>&1 133 | if [ "$STREAMORRECORD" == "both" ] 134 | then 135 | streamlink "$LIVE_URL" "1080p,720p,best" -o - | ffmpeg -re -i pipe:0 \ 136 | -codec copy -f mpegts "${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}" \ 137 | -vcodec copy -acodec aac -strict -2 -f flv "${RTMPURL}" \ 138 | > "${LOGFOLDER}${FNAME}.streaming.log" 2>&1 139 | STREAMSUCCESS=$? 140 | elif [ "$STREAMORRECORD" == "record" ] 141 | then 142 | streamlink --loglevel trace -o "${SAVEFOLDER}${FOLDERBYDATE}/${FNAME}" \ 143 | "$LIVE_URL" "1080p,720p,best" > "${LOGFOLDER}${FNAME}.log" 2>&1 144 | elif [ "$STREAMORRECORD" == "stream" ] 145 | then 146 | streamlink "$LIVE_URL" "1080p,720p,best" -o - | ffmpeg -re -i pipe:0 \ 147 | -vcodec copy -acodec aac -strict -2 -f flv "${RTMPURL}" \ 148 | > "${LOGFOLDER}${FNAME}.streaming.log" 2>&1 149 | fi 150 | # backup stream if autobackup is on 151 | sleep 5 152 | if [ "$AUTOBACKUP" == "on" ] && [ "$STREAMORRECORD" != "stream" ] 153 | then 154 | if ([ "$STREAMORRECORD" == "record" ] && tail -n 5 "${LOGFOLDER}${FNAME}.log"|grep -q "Stream ended") || [ "X$STREAMSUCCESS" == "X0" ] 155 | then 156 | ./autobackup.sh $NAME $SITE $FOLDERBYDATE $FNAME & 157 | else 158 | echo "$LOG_PREFIX stream record fail, check ${LOGFOLDER}${FNAME}.log and ${LOGFOLDER}${FNAME}.streaming.log for detail." 159 | fi 160 | fi 161 | 162 | # Exit if we just need to record current stream 163 | LOG_PREFIX="$(date +"[%Y-%m-%d %H:%M:%S]") ===$SITE===" 164 | echo "$LOG_PREFIX Live stream recording stopped." 165 | [[ "$LOOPORONCE" == "once" ]] && break 166 | done 167 | --------------------------------------------------------------------------------