下面的指令使用 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)&