下面的命令使用 sed 处理 youtube-dl 的输出以获取视频的文件名
youtube-dl "$URL" 2> /dev/null | \
sed -n 's/^\[download\] Destination: //p; s/^\[download\] \(.*\) has already been downloade.*/\1/p'
在 youtube-dl 完成获取和解析 HTML 并开始下载视频(开始执行后几秒/几秒)后,它会立即输出下载完成后视频的文件名(后缀为下载时的一段.part
时间) )
所以问题的关键和我所坚持的问题是,如何将上面的命令放到后台(以便它不断下载)并从其标准输出中获取视频文件名,以便我可以使用它来打开视频文件下载完成之前。
答案1
你可以使用inotifywait
:
$ youtube-dl "$URL" &
$ inotifywait --event create --format '"%f"' . | xargs vlc
那里存在一个竞争条件,如果您的连接速度非常快(我现在是),则可以在播放器打开文件之前下载并重命名该文件。另外,如果youtube-dl
单独下载音频和视频之类的操作,您可能最终会打开错误的文件。
答案2
@fra-san 的评论让我想起了 whileread
循环,您可以使用它来逐行/按程序处理输出(而不是使用管道在功能上),您可以使用运算<
符将文件的输出通过管道传输到该循环使用 Bash Process 替换 youtube-dl 命令,您还可以通过添加一个 while 循环将其发送到后台,&
并且 while 循环仍然可以读取它的输出(它只是读取 BPS 制作的文件)。
通过测试我发现即使下载完成并重命名后我也可以继续正常播放视频,尽管这可能是mpv的一个功能。
#!/bin/bash
# ytdl-stream - use youtube-dl to stream videos i.e watch videos as they download
# usage: ytdl-stream [YOUTUBE_DL_OPTIONS] URL
# you can pipe into it a command to open you video player, e.g:
# echo mpv --mute=yes | ytdl-stream -f 'best[width<=1920,height<=1080]' --write-auto-sub [URL]
test ! -t 0 && player_cmd="$(cat /dev/stdin)" || player_cmd="mpv"
while IFS="" read -r line; do
filename=$(echo "$line" | sed -n 's/^\[download\] Destination: //p')
if [[ -z "$filename" ]]; then
filename=$(echo "$line" | sed -n 's/^\[download\] \(.*\) has already been downloade.*/\1/p')
[[ -z "$filename" ]] && continue || notify-send "file already downloaded, opening.."
else
notify-send "downloading.."
fi
withoutExtensions="${filename%.*}"
withoutExtensions="${withoutExtensions%.*}"
if [[ -e "$filename" ]]; then
sleep 0.5 && ($player_cmd "$filename")&
elif [[ -e "$filename".part ]]; then
sleep 2
if [[ -e "$filename".part ]]; then
notify-send "found .part after sleep again"
($player_cmd "$filename".part)&
else
sleep 0.5 && ($player_cmd "$withoutExtensions"*)&
fi
fi
done < <(youtube-dl "$@" 2> /dev/null)&