blob: 6b6560007100c69df3c38fb4da9dcf2e797acbfe (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#!/bin/sh
ytdl_cmd_base="yt-dlp --continue --embed-metadata --ignore-errors --no-force-overwrites --no-playlist --verbose"
simulation_cmd="yt-dlp --simulate --print %(filename)s"
case "$BROWSER" in
*firefox*) cookies="firefox" ;;
*librewolf*) cookies="firefox:~/.librewolf/$USER.default" ;;
*qutebrowser*) cookies="chromium:~/.local/share/qutebrowser" ;;
esac
if [ -n "$cookies" ]; then
ytdl_cmd_base="$ytdl_cmd_base --cookies-from-browser \"$cookies\""
fi
shift $((OPTIND - 1))
# Use the first non-option argument as the URL if provided, else from clipboard
# [url] [type] [cmd]
if [ $# -eq 1 ]; then
type="$1"
url="$(xclip -selection clipboard -o)"
elif [ $# -eq 2 ]; then
if echo "$1" | grep -qE "https?://"; then
url="$1"
elif echo "$2" | grep -qE "https?://"; then
type="$1"
url="$2"
fi
fi
# Process command-line options for download type
case $type in
-m | --music | m | music)
download_type="music"
output_dir="${XDG_MUSIC_DIR:-${HOME}/Music}"
archive_file="${XDG_DOTFILES_DIR:-${HOME}/.dotfiles}/global/Music/.music.txt"
ytdl_output_format="${output_dir}/%(artist|)s%(artist& - |)s%(title)s.%(ext)s"
ytdl_cmd_base="$ytdl_cmd_base --audio-format best --audio-quality 0 --download-archive \"$archive_file\" --extract-audio --recode-video mp3"
;;
-r | --restore | r | restore)
output_dir="${XDG_MUSIC_DIR:-${HOME}/Music}"
archive_file="${XDG_DOTFILES_DIR:-${HOME}/.dotfiles}/global/Music/.music.txt"
ytdl_output_format="${output_dir}/%(artist|)s%(artist& - |)s%(title)s.%(ext)s"
ytdl_cmd_base="$ytdl_cmd_base --audio-format best --audio-quality 0 --extract-audio --recode-video mp3"
ytdl_cmd="$ytdl_cmd_base --output \"$ytdl_output_format\""
[ ! -f "$archive_file" ] && exit 1
while read -r line; do
video_id=$(echo "$line" | awk '{print $2}')
ytdl_cmd="$ytdl_cmd_base --output \"$ytdl_output_format\" \"https://www.youtube.com/watch?v=$video_id\""
idnum=$(tsp bash -c "$ytdl_cmd")
pkill -RTMIN+21 "${STATUSBAR:-dwmblocks}"
done <"$archive_file"
exit 0
;;
-v | --video | v | video)
download_type="video"
output_dir="${XDG_VIDEOS_DIR:-${HOME}/Videos}"
ytdl_output_format="${output_dir}/%(title)s [%(id)s].%(ext)s"
video_ext=$(printf "best\n60fps\n30fps\nmp4\nmkv" | dmenu -i -p "Choose an encoding (default: 1080p)") || exit
case $video_ext in
best)
video_formats="--format bestvideo+bestaudio/best"
;;
60fps)
video_formats='--format "((bv*[fps=60]/bv*)[height<=1080]/(wv*[fps=60]/wv*)) + ba / (b[fps=60]/b)[height<=1080]/(w[fps=60]/w)"'
;;
30fps)
video_formats='--format "((bv*[fps=30]/bv*)[height<=1080]/(wv*[fps=30]/wv*)) + ba / (b[fps=30]/b)[height<=1080]/(w[fps=30]/w)"'
;;
*)
video_formats="--format bestvideo+bestaudio/best"
video_options="--recode-video $video_ext"
;;
esac
ytdl_cmd_base="$ytdl_cmd_base --buffer-size 1M --embed-thumbnail $video_formats --no-sponsorblock $video_options"
ytdl_cmd_base="${ytdl_cmd_base%* }"
;;
*)
notify-send "⛔ Invalid option: -$OPTARG"
exit 1
;;
esac
[ -z "$url" ] && notify-send "⛔ No URL provided and clipboard is empty or does not contain a valid URL." && exit 1
# Validate the URL format
! echo "$url" | grep -qE '^https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9./?&%=_-]*)?$' && notify-send "⛔ Invalid URL format: $url" && exit 1
# Validate URL accessibility
! curl --head --silent --fail "$url" >/dev/null && notify-send "⛔ URL is not accessible: $url" && exit 1
case $url in
*playlist* | *list=*)
pl_download_choice=$(printf "playlist\na content" | dmenu -i -p "Download entire playlist or just this content?")
[ "$pl_download_choice" = "playlist" ] &&
ytdl_cmd_base=$(echo "$ytdl_cmd_base" | sed 's/ --no-playlist//') &&
ytdl_cmd_base="$ytdl_cmd_base --yes-playlist" &&
echo >/tmp/qplaylist
[ "$download_type" = "video" ] &&
channel=$(yt-dlp --print "%(channel)s" "$url" | head -n 1 | sed 's/, /,/g;s/[\/:*?"<>| ]/-/g' | tr '[:upper:]' '[:lower:]') &&
playlist=$(yt-dlp --print "%(playlist_title)s" "$url" | head -n 1 | sed 's/, /,/g;s/[\/:*?"<>| ]/-/g' | tr '[:upper:]' '[:lower:]') &&
subdir="${channel}/${playlist}" &&
mkdir -p "${output_dir}/${subdir}" &&
ytdl_output_format="${output_dir}/${subdir}/%(playlist_index)02d_%(title)s [%(id)s].%(ext)s"
;;
esac
simulation_cmd="$simulation_cmd --cookies-from-browser $cookies $url"
ytdl_cmd="$ytdl_cmd_base --output \"$ytdl_output_format\" \"$url\""
# Notify and perform simulation to get filename (feedback to user)
echo "$simulation_cmd" | while IFS= read -r line; do
filename=$(basename "$line")
notify-send "📥 Queuing $download_type to download:" "$filename"
done
# Enqueue the download task with tsp
filename=$($simulation_cmd 2>/dev/null)
[ -f /tmp/qplaylist ] && rm -rf /tmp/qplaylist
notify-send "⏳ Downloading $download_type:" "$filename"
idnum=$(tsp bash -c "$ytdl_cmd")
pkill -RTMIN+21 "${STATUSBAR:-dwmblocks}"
# Notify upon completion
tsp -D "$idnum" notify-send "✅ $download_type download complete:" "$url" ||
notify-send "❌ Faild to download:" "$url"
# Conditionally update the music database if the download type is music
[ "$download_type" = "music" ] && tsp -D "$idnum" bash -c "mpc update"
|