Skip to content

Instantly share code, notes, and snippets.

@Misko-2083
Created April 27, 2018 18:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Misko-2083/86dcb64ed2e22c7b7bc6785b5e02b3aa to your computer and use it in GitHub Desktop.
Save Misko-2083/86dcb64ed2e22c7b7bc6785b5e02b3aa to your computer and use it in GitHub Desktop.
youtube-dl wrapper with yad paned dialog UI
#!/bin/bash
### Itchy video
### Downloads videos (with the best video + best audio or best option available) into ~/Videos
### If ffmpeg or avconv is installed, best video & best audio will be downloaded separately
### and combined into a single file
### Requires: xev (provided by "x11-utils" package), xdotool, yad, youtube-dl, wget
### Note: uses xev with -event option (so, should work in debian jessie or newer)
### Made by Misko_2083
# ***********************
# DEPENDANCY CHECK
# ***********************
ERR(){ echo "ERROR: $1" 1>&2; }
declare -i DEPCOUNT=0
for DEP in /usr/bin/{xev,xdotool,yad,youtube-dl,wget}; {
[ -x "$DEP" ] || {
ERR "$LINENO Dependency '$DEP' not met."
DEPCOUNT+=1
}
}
[ $DEPCOUNT -eq 0 ] || exit 1
# ***********************
# END DEPENDANCY CHECK
# ***********************
# ***********************
# INITIALIZATION
# ***********************
# Download location
export SAVEDIR="$HOME/Videos"
cd "${SAVEDIR}"
# Command for running download_video function
# Later will be used by yad
export ytdownload='@bash -c "download_video %1"'
# We need this to store the youtube Link
export ytlink=$(mktemp /tmp/ytlnk.XXXXXXXX)
# Temp files paths
export ytdpipe=$(mktemp -u /tmp/ytd.XXXXXXXX)
export ytdpipetwo=$(mktemp -u /tmp/ytd2.XXXXXXXX)
# Make named pipes
mkfifo "$ytdpipe"
mkfifo "$ytdpipetwo"
# Initialize the key for the paned dialog plugs
ytdkey=$(($RANDOM * $$))
# ***********************
# END INITIALIZATION
# ***********************
# ***********************
# FUNCTIONS
# ***********************
# ------------------
function on_exit {
# ------------------
# Removes temorary files
rm -f "$ytdpipe"
rm -f "$ytdpipetwo"
rm -f "$ytlink"
}
trap "on_exit" EXIT
# ------------------
function download_video () {
# ------------------
# Disables fbtn in first yad plug tab
# fbtn is the second field
echo "2:@disabled@"
# Check if the URL is valid with the spider
if wget -q --spider "$1"; then
# Export url to a temp file for later use
echo "${1}" >> "$ytlink"
echo "#Preparing to download" >> "$ytdpipe"
# Loop that gets percentage and progress from the second named pipe ($ytdpipetwo),
# writes them to first named pipe ($ytdpipe)
while read line; do
# Filters lines with percentage
if [[ "$(echo $line | grep '[0-9]*%')" ]];then
percent=$(echo $line | awk '{print $2}')
echo "${percent%.*}" >> "$ytdpipe"
fi
# Filters lines with '[download\]'
if [[ "$(echo $line | grep '\[download\]')" ]];then
progress=$(echo $line | awk '{$1=""; print $0}')
echo "#$progress" >> "$ytdpipe"
fi
done < "$ytdpipetwo" &
LOOP_PID="$!"
# Downloads video
# output is redirected to the second named pipe ($ytdpipetwo)
youtube-dl -f 'bestvideo [ext = mp4] + bestaudio [ext = m4a] / bestvideo + bestaudio / best' --merge-output-format mp4 --newline -i -o "%(title)s.%(ext)s" "${1}" 2>&1 >> $ytdpipetwo &
ytproc_pid=$!
wait $ytproc_pid 2>/dev/null # supress message from kill command later, wait also returns exit status
if [[ "$?" = 0 ]]
then
echo "0" >> "$ytdpipe"
echo "#Download complete." >> "$ytdpipe"
kill "$LOOP_PID"
elif [[ ! -s "$ytdpid" ]]; then
echo "#Download canceled." >> "$ytdpipe"
echo "0" >> "$ytdpipe"
else
echo "#Download error" >> "$ytdpipe"
kill "$LOOP_PID"
fi
else
echo "#Invalid URL" >> "$ytdpipe"
fi
# Enables fbtn in the first yad plug tab
# fbtn is the second field
echo "2:$ytdownload"
}
export -f download_video
# ------------------
function ytdl_version () {
# ------------------
# This function checks for new youtube-dl version
# If youtube-dl is latest, writes "up-to-date" to the progress bar
# If tit isn't, writes "update is available" to the progress bar
echo "#Checking youtube-dl version" >> "$ytdpipe"
wget --spider --user-agent="Mozilla/5.0 Gecko/20100101" --timeout=30 -q "https://rg3.github.io/youtube-dl/" -O /dev/null
if [[ "$?" -ne "0" ]]; then
echo "#Can't connect to youtube-dl server site" >> "$ytdpipe"
fi
ytdlcv=$(youtube-dl --version)
ytdllv=$(wget -O- -q "https://rg3.github.io/youtube-dl/update/LATEST_VERSION")
if [[ "$ytdlcv" == "$ytdllv" ]]; then
echo "#youtube-dl is up-to-date" >> "$ytdpipe"
else
echo "#youtube-dl update is available" >> "$ytdpipe"
fi
}
export -f ytdl_version
# ------------------
function stop_clicked () {
# ------------------
# This function is executed when the stop button in the main yad dialog is clicked
# Finds youtube-dl process and kills it
if [[ ! -s "${ytlink}" ]]; then
echo "#Nothing to stop." >> "$ytdpipe"
else
YoutubeLink="$(tail -1 "${ytlink}")"
YtCommand="youtube-dl -f bestvideo [ext = mp4] + bestaudio [ext = m4a] / bestvideo + bestaudio / best --merge-output-format mp4 --newline -i -o %(title)s.%(ext)s $YoutubeLink"
YoutubePID="$(ps -eo pid,cmd | grep -F "$YtCommand" | grep -v "grep" | awk '{ print $1 }')"
if [[ "$YoutubePID" != "" ]]; then
kill -9 $YoutubePID
else
echo "#Nothing to stop." >> "$ytdpipe"
fi
fi
}
export -f stop_clicked
# ***********************
# END FUNCTIONS
# ***********************
# ***********************
# MAIN
# ***********************
# Open the name pipe on file descriptor 3
exec 3<> $ytdpipe
# First paned tab
# Form with entrey and download button
yad --plug="$ytdkey" --tabnum=1 --form --field "Enter video url":CE "" \
--image=browser-download --field="Download!browser-download:fbtn" "$ytdownload" &
# Second paned tab
# progress bar
yad --plug="$ytdkey" --tabnum=2 --window-icon="$ICON" \
--progress --borders=6 --auto-close --auto-kill <&3 &
echo "#Enter video URL." >> "$ytdpipe"
#ytdl_version &)"
# main window
yad --class="Itchy" --paned --key="$ytdkey" \
--button="Check yoututube-dl":'bash -c "ytdl_version" 2>/dev/null' \
--button="Stop":'bash -c "stop_clicked" 2>/dev/null' --text="Enter the video or playlist URL and click Download" \
--width=500 --height=200 --border=9 \
--title=$"Itchy video" --window-icon="browser-download" --center &
YPID="$!"
# ***********************
# END MAIN
# ***********************
# Wait untill main window opens, that is until window name appears
until xdotool getwindowname "$(xdotool search --any --pid $YPID --class "Itchy" 2>/dev/null | tail -1 2>/dev/null)" &>/dev/null; do
# sleep until the window opens
sleep .1
done
# Decimal window id
WindowID="$(xdotool search --any --pid $YPID --class "Itchy" 2>/dev/null | tail -1)"
# Hexadecimal
WindowIDHex=$(printf "0x%08x" ${WindowID})
# Base seven
WindowBSeven=$(printf "0x%07x" ${WindowID})
# This is needed because youtube-dl prevents one yad plug tab from closing
# We have to find out when the main dialog is closed
# Monitor for DestroyNotify event of the main yad window and kill youtube-dl
xev -event structure -id ${WindowIDHex} 2>/dev/null |
while IFS=$',' read -a A; do
# If main window is closed
if [[ "${A[0]}" =~ "DestroyNotify event" ]]; then
YoutubeLink="$(tail -1 "${ytlink}")"
YtCommand="youtube-dl -f bestvideo [ext = mp4] + bestaudio [ext = m4a] / bestvideo + bestaudio / best --merge-output-format mp4 --newline -i -o %(title)s.%(ext)s $YoutubeLink"
YoutubePID="$(ps -eo pid,cmd | grep -F "$YtCommand" | grep -v "grep" | awk '{ print $1 }')"
if [[ "$YoutubePID" != "" ]]; then
kill -9 $YoutubePID
fi
# xev has to be killed too or it will run forever
XevPID="$(ps -eo pid,cmd | grep "xev -event structure -id $WindowIDHex" | grep -v "grep" | awk '{ print $1 }')"
kill $XevPID
wait $XevPID 2> /dev/null
fi
A=()
done & xev_pid=$!
# Wait until yad window closes
wait $YPID
# Wait also returns exit status
# If we need exit status of the main window can get it here
# echo $?
# Wait until process with pid xev_pid finishes
# This is needed to properly remove temp files
wait $xev_pid
# Removing *.part file(s)
YoutubeLink="$(tail -1 "${ytlink}")"
if [[ "${YoutubeLink}" != "" ]]; then
# Offer cleanup
if yad --text="Do you want Itchy video to search and remove any *.part file(s) left?" \
--button="Yes!gtk-yes:0" --button="No!gtk-no:1" --timeout=10 --timeout-indicator=right \
--title=$"Itchy video" --window-icon="browser-download" --image=browser-download --border=9
then
echo "Searching for any *.part file from the most recent download attempts"
OIFS="$IFS" # backup internal field separator
IFS=$'\n'
for LNK in $(<${ytlink}); do
Fname="$(youtube-dl --get-filename -o "%(title)s" "${LNK}")"
echo "${Fname}"
rm "$(find "${SAVEDIR}" -type f -name "*${Fname}.*" | grep part)" &>/dev/null # Finds & removes the part file
done
# restores internal field separator
IFS="$OIFS"
fi
fi
# Close file descriptor 3
exec 3>&-
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment