我正在尝试编写一个 bash 脚本来下载给定公共 YouTube 播放列表中的所有视频。以下是我目前所做的:
#!/bin/bash
# Default values
decode_video=true
output_format="avi"
audio_codec="libmp3lame"
audio_bitrate="192k"
audio_sample_rate="44100"
audio_channels="2"
video_codec="libxvid"
video_quality="3"
# Function to download and convert each video
download_and_convert() {
local video_url="$1"
local output_name="$2"
# Show download start message
echo "Downloading: $output_name.mp4..."
# Download the video
yt-dlp --progress -f "bv*+ba/b" --merge-output-format mp4 "$video_url" -o "$output_name.mp4"
# Show download end message
echo "Downloaded: $output_name.mp4"
# Check if video should be re-encoded
if $decode_video; then
# Debug: Output the values of the variables
echo "output_name: \"$output_name\""
echo "video_codec: $video_codec"
echo "video_quality: $video_quality"
echo "audio_codec: $audio_codec"
echo "audio_sample_rate: $audio_sample_rate"
echo "audio_bitrate: $audio_bitrate"
echo "audio_channels: $audio_channels"
# Re-encode video to MPEG-4 (Xvid) and convert audio to MP3
echo "Converting video to MPEG-4 (Xvid) and audio to MP3..."
# Ensure that the script runs the command directly without any prompt
ffmpeg -hide_banner -i "$output_name.mp4" -c:v libxvid -qscale:v 3 -c:a libmp3lame -ar 44100 -b:a 192k -ac 2 "$output_name.avi"
else
# Copy the video and only convert audio
echo "Copying video and converting audio to MP3..."
ffmpeg -i "$output_name.mp4" -c:v copy -c:a $audio_codec -ar $audio_sample_rate -b:a $audio_bitrate -ac $audio_channels "$output_name.$output_format"
fi
# Clean up the original MP4 file
#rm "$output_name.mp4"
echo "Converted: $output_name.$output_format"
}
# Parse command-line options
while [[ $# -gt 0 ]]; do
case $1 in
--no-decode-video)
decode_video=false
shift
;;
--decode-video)
decode_video=true
shift
;;
*)
playlist_url="$1"
shift
;;
esac
done
# Ensure playlist URL is provided
if [ -z "$playlist_url" ]; then
echo "Usage: $0 <playlist_url> [--no-decode-video]"
exit 1
fi
# Get total number of videos in the playlist
total_videos=$(yt-dlp -j --flat-playlist "$playlist_url" | jq -r '.id' | wc -l)
echo "Total videos in playlist: $total_videos"
# Download the playlist and process each video
current_video=1
yt-dlp -j --flat-playlist "$playlist_url" | jq -r '.id' | while read -r video_id; do
# Define output filename
output_name="video_$video_id"
# Show progress
echo "Processing video $current_video of $total_videos..."
# Download and convert the video
download_and_convert "https://www.youtube.com/watch?v=$video_id" "$output_name"
# Increment video counter
current_video=$((current_video + 1))
done
echo "All videos processed successfully!"
现在,可以下载视频,但转换ffmpeg
失败。它开始显示常规ffmpeg
输出,就像它正在正确转换一样,然后显示:Parse error, at least 3 arguments were expected, only 1 given in string 'GC1Y0'
。那可能是什么?我在另一个帖子中看到,引用文件名时存在问题。
该错误由代码中的函数报告
check_keyboard_interaction()
,因此看起来它正在尝试从其标准输入读取并尝试将那里的内容解释为进一步的指令。这里
ffmpeg
的 stdin 将成为不应读取的管道jq
。ffmpeg
您需要使用该-nostdin
选项禁用 stdin 交互。或者,您可以执行以下操作,而不是执行
yt-dlp -j --flat-playlist "$playlist_url" | jq -r '.id'
两次并将输出第二次提供给循环:while
yt-dlp
(但要注意的是和的退出状态jq
会丢失)然后使用获取计数
"${#list[@]}"
并循环它们for video_id in "${list[@]"
而不是while read
循环,在这种情况下,的标准输入ffmpeg
将保持不变,从而允许用户在从终端调用该脚本时与其进行交互。关于您的代码的一些其他说明:
info() { printf>&2 '%s\n' "$@"; }
它还有助于:echo
不能用于任意数据,请printf
改用。echo Downloaded...
是或,echo Converted...
但您没有检查前几个命令的退出状态来检查它是否真的被下载或转换|| return
。您应该在yt-dl
/命令中添加一些ffmpeg
。read -r line
不是读取一行的命令。请参阅了解“IFS= read -r line” 。不过这可能不是问题,因为您没有进行修改,而且读取的内容不太可能包含默认值中的字符。$IFS
$IFS
我并不熟悉,
ffmpeg
但从 shell 的角度来看,唯一明显可能的问题是:将其(添加引号)更改为