#!/bin/bash

# NAME:         YAD Youtube Downloader
#
# DESCRIPTION:  youtube-dl frontend for YT videos
#
# This script is a fork of the script by "damo" from BunsenLabs
# MAINTAINER: Misko_2083 <Miloš Pavlović> June 2016
#
# June 2016
# New: Format selection dialog
#      Multiprogress bars
#      *  Progress bar method is improved version of Glutanimate's yad_wget script
#      *  yad-wget https://github.com/Glutanimate/misc-scripts/blob/master/Internet/yad_wget
#      New GUI with multi-download options
#      Simultaneous downloads of videos
#      Option to chose the number of simultaneous downloads
#
# August 2016
# New: Support for lists
#      Auto-detection if a URL is a list or a video
#      Option to download videos from a list
#      An option to select all/none
# Improved: Format selection dialog data
#
# March 2017
# New:  Progress bar while loading the format info
#       Window icon is stored in the script
#	Check for youtube-dl version
# Improved: Dialog Wording and appearance

# ***********************
# INITIALIZATION
# ***********************

declare -i SIMULTANEOUS
declare -i FIELDS
SVG='<''svg width="48" height="48" viewBox="0 0 245 245">
    <radialGradient fx="5%" fy="5%" id="rg" r="65%">
      <stop offset="0%" stop-color="white"/>
      <stop offset="100%" stop-color="lightgray"/>
    </radialGradient>
    <radialGradient fx="5%" fy="5%" id="gr" r="65%">
      <stop offset="0%" stop-color="#932420"/>
      <stop offset="100%" stop-color="#CB322C"/>
    </radialGradient>
    <linearGradient id="lg" gradientUnits="userSpaceOnUse">
      <stop offset="0" stop-color="#932420"/>
      <stop offset="1" stop-color="#CB322C"/>
    </linearGradient>
  <rect width="235" x="5" y="5" fill="url(#rg)" rx="30"
  height="235" ry="30" stroke="white" stroke-width="4"
  stroke-opacity="0.4"/>
  <rect width="215" x="16" y="115" fill="url(#gr)" rx="50"
  height="115" ry="50" stroke="white" stroke-width="2"
  stroke-opacity="0.4"/>
  <g>
   <text x="50%" y="42%" text-anchor="middle" stroke="none" fill="black"
    font-family="Sans" font-size="90" font-weight="800">You</text>
   <text x="50%" y="82%" text-anchor="middle" stroke="none" fill="white"
    font-family="Sans" font-size="70" font-weight="800">Tube</text>
   </g>
</svg>'

# Set GUI variables up
TITLE="YAD Pobieracz YouTube"    # dialog title
# Progress dialog text
TEXT="<b>Pobieranie</b> ...
Anuluj i wyczyść - usuwa pliki *.part
Anuluj - Anuluje pobieranie"
ICON="/tmp/yt.svg"
if [ ! -f "$ICON" ]; then
    echo "SVG file not found. Creating it."
	echo "$SVG" > "$ICON"
fi

IMAGE="$ICON"
declare -i MODE
MODE=1     # Defaiult dialog mode: 0 - Multi, 1 - Manual
#Multy download dialog options
SIMULTANEOUS=2    # set default number of simultaneous downloads (1-5)
FIELDS=8          #  number of URL fields
# List checkboxes (default mode) TRUE/FALSE
SELECT_ALL="TRUE"
# Set global variables (Do not change)
FORMAT=""  # Set global variable for the format selection
ENTRY=""   # Set global variable for the entry
# Check if yad is installed
if ! hash yad &>/dev/null;then
    echo "Nie znaleziono yad"
    echo "Zainstaluj yad i uruchom skrypt ponownie"
    exit
fi
# Check if youtube-dl is installed
if ! hash youtube-dl &>/dev/null;then
    DLG=$(yad --form \
        --borders=10 --image-on-top \
        --text="   Nie znaleziono youtube-dl \n\n  Zainstaluj youtube-dl i uruchom skrypt ponownie" --button="gtk-ok:0" \
        --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" \
    )
    exit
fi
# Check if ffmpeg is installed
if ! hash ffmpeg &>/dev/null;then
    DLG=$(yad --form \
        --borders=10 --image-on-top \
        --text="   Nie znaleziono ffmpeg \n\n  Zainstaluj ffmpeg i uruchom skrypt ponownie" --button="gtk-ok:0" \
        --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" \
    )
    exit
fi
# Check if jq is installed
if ! hash jq &>/dev/null;then
    DLG=$(yad --form \
        --borders=10 --image-on-top \
        --text="   Nie znaleziono jq\n\n  Zainstaluj jq i uruchom skrypt ponownie" --button="gtk-ok:0" \
        --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" \
    )
    exit
fi

# ***********************
# END INITIALIZATION
# ***********************


# ***********************
# FUNCTIONS
# ***********************

# ------------------
function download()
# ------------------
{
	# Download function
	# Passed: $1 - TYPE
	#         $2 - URL
	#         $3 - COUNTER (to identify the bar)

	# Checks if the TYPE is a playlist
	#  and adds apropriate option to UTYPE variable
	if [[ "$1" == "playlist?list" ]]; then
	UTYPE="--yes-playlist"                # if a playlist
	else
	UTYPE=""                              # if a video
	fi
	cd "$SAVEDIR"   # Changes current path
	# Starts the download and pipes the output to a loop
	# Loop is used to display the text in multi-progressbar
	youtube-dl ${UTUBE} ${UTYPE} --newline -i -o "%(title)s-%(id)s.%(ext)s" "https://www.youtube.com/$1=$2" 2>&1 \
	| while read -r line; do
		if [[ "$(echo $line | grep '[0-9]*%')" ]];then
			percent=$(echo $line | awk '{print $2}')
			if [[ ! "$(echo "${percent}" | grep "100")" ]]; then  # do not print 100% yet in case of conversion (mp3) or playlist
				echo "$3:${percent%.*}"                            # sends percentage to the progress bar
			fi
		fi
		if [[ "$(echo $line | grep -E '\[download\]|\[ffmpeg\]')" ]];then
			progress=$(echo $line | awk '{$1=""; print substr ($0, 0, 75)}')
			echo "$3:#$progress"       # sends text to the progressbar
		fi
	done
    RET_YT="${PIPESTATUS[0]}"
    if [[ "$RET_YT" = 0 ]]
      then
          echo "$3:100%"
          echo "$3:#Pobieranie zakończone."

      else
          echo "$3:#Błąd pobierania."
    fi
}

# ------------------
function format_selection()
# ------------------
{
	# Format selection

	# Temp file to store the items for the list
	res=$(mktemp --tmpdir ytlist.XXXXXXXX)
   CNT=0
   while [  $CNT -lt 1 ]; do
        echo "5"
	# Fetching available format data and redirecting to res temp file
	youtube-dl -j --skip-download --all-formats "$YTEMP" --newline \
	| jq -r '.format_id, .format, .ext,
	if .vcodec == "none" then "audio only" else .vcodec end,
	if .acodec == "none" then "video only" else .acodec end,
	if .filesize == null then "" else .filesize/1024/1024 end' > $res
	# Checks youtube-dl return status
	if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
		yad --form \
		--borders=10 --image-on-top \
		--text="Nie można pobrać listy dostępnych formatów\nSprawdź połączenie internetowe lub zaktualizuj youtube-dl" --button="gtk-ok:0" \
		--center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE"
		rm -f $res  # rm temp file
		main        # go back
	fi
	# temp file for awk to write to
	res2=$(mktemp --tmpdir ytlist.XXXXXXXX)
	# awk converts  every sixth line (if not empty) to two decimal places and adds MiB
	awk '{if (NR % 6 == 0 && $1 !=""){printf("%.2f MiB\n", $1)} else {print $0}}' $res > $res2
	cp -f $res2 $res
	rm -f $res2
        CNT=$(($CNT+1))
    done | yad --progress --pulsate --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" --auto-close \
						--borders=10 --button="Anuluj!gtk-no:1" --text="Pobieranie informacji o formatach..."
    RET=$?
	case "$RET" in
		0) # Continue
		;;
		1) # Canceled
			rm -f $res2  # rm temp file
			rm -f $res  # rm temp file
			main
		;;
		*)
			rm -f $res2  # rm temp file
			rm -f $res  # rm temp file
			main
		;;
	esac
	# Calls format (list) selection dialog
	FORMAT="$(yad --list --width=600 --height=500 --hide-column=1 --column="format"  \
       --column="format" --column="extension" --column=video --column="audio" --column="filesize" \
       --button="wróć!back:2" --button="Odśwież!reload:3" --button="Wyjdź!gtk-cancel:1" --button="Pobierz!gtk-ok:0" \
       --window-icon="$ICON" --image="$IMAGE" --image-on-top \
       --text "$FILENAME\nWybierz format do pobrania" --borders=10 \
       --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" \
       < "$res" )"
    RET=$?
	case "$RET" in
		0) # Continue
		;;
		1) # Canceled
			rm -f $res  # rm temp file
			exit
		;;
		2) # Back
			rm -f $res  # rm temp file
			main
		;;
		3) # Refresh
			rm -f $res  # rm temp file
			format_selection
		;;
		*) # Default
			rm -f $res  # rm temp file
			exit
		;;
	esac
    rm -f $res  # rm temp file
    FORMAT=$(echo "$FORMAT" | cut -d '|' -f 1)
	if [[ -z $FORMAT ]];then
		yad --text="Nie wybrałeś formatu do pobrania\nCzy chcesz powrócić do głównego okna?" \
		--borders=10 --form --button="Nie!gtk-cancel:1" --button="Tak!gtk-ok:0" \
		--center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE"
		RET=$?
		case "$RET" in
		0)          # Back
			main
		;;
		*)          # Cancelled
			exit
		;;
		esac
	fi
}

# ------------------
function list_selection()
# ------------------
{
    # Temp file to store the items from a list
    res=$(mktemp --tmpdir ytlist.XXXXXXXX)
    youtube-dl -j --flat-playlist "https://www.youtube.com/playlist?list=${YTEMP}" \
    | jq -r '.title, .id' | sed '1~2s/^/'"$SELECT_ALL"'\n/' \
    | yad --text='Select items to download' --list --checklist --column "Select" --column "Title" --column "Url" --no-markup \
       --button="$(if [[ "$SELECT_ALL" = "TRUE" ]]; then echo Select None; else echo Select All; fi)!gtk-yes:4" \
       --button="back!back:2" --button="Refresh!reload:3" --button="Exit!gtk-cancel:1" --button="Download!gtk-ok:0" \
       --window-icon="$ICON" --image="$IMAGE" --image-on-top \
       --borders=10 --width=600 --height=500 --print-column=3 --separator=" " \
       --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" > $res
    RET=$?
    case "$RET" in
       0)          # Continue
       ;;
       1)          # Canceled
       rm -f $res  # rm temp file
       exit
       ;;
       2)          # Back
       rm -f $res  # rm temp file
       main
       ;;
       3)          # Refresh
       list_selection
       ;;
       4)          # Select All/None
       if [[ "$SELECT_ALL" = "TRUE" ]]; then
          SELECT_ALL="FALSE"
       else
          SELECT_ALL="TRUE"
       fi
       list_selection
       ;;
       *)
       rm -f $res  # rm temp file
       exit
       ;;
   esac
    # Checks if temp file is empty
    if [[ ! -s "$res" ]];then
        yad --text="At least one item needs to be selected\nDo you want to return to the main window?" \
        --borders=10 --form --button="No!gtk-cancel:1" --button="Yes!gtk-ok:0" \
        --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE"
        RET=$?
        case "$RET" in
           0)          # Back
           rm -f $res  # rm temp file
           main
           ;;
           *)          # Canceled
           rm -f $res  # rm temp file
           exit
           ;;
        esac
    fi
	# Starts the download function
	list_download
}

# ------------------
list_download()
# ------------------
{
	i=0
	TOTAL=$(wc -l "$res" | cut -d ' ' -f 1)
	cd "$SAVEDIR"
	while read -r line || [[ -n "$line" ]]; do
		i=$(($i+1))
		PERCENT=$(($i*100/${TOTAL}))           # Calculates percentage
		echo "#Pobieranie $i/$TOTAL: $line"   # Writes to the progress-bar
		youtube-dl ${UTUBE} --newline -i -o "%(title)s-%(id)s.%(ext)s" "https://www.youtube.com/watch?v=${line}"   2>&1  &
		PID="$!"
		wait "$PID"
		echo "$PERCENT"
	done < "$res" | yad --progress --center --text="Downloading list items" --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" --auto-close \
						--borders=10 --button="Anuluj!gtk-no:1"
	if (( $? == 1 ));then                 # Download canceled, so clean up
		kill "$PID" &>/dev/null         # Kills any running download process

		notify-send -t 3000 --icon "dialog-info" "Pobieranie anulowane"
		while read -r line || [[ -n "$line" ]]; do
			rm "$(find "$SAVEDIR" -type f -name "*-$line.*" | grep part)" &>/dev/null   # Finds & removes the part file
			echo "#$line"
			sleep "0.1"
		done < "$res" | yad --progress --pulsate --center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" --auto-close \
						--borders=10 --button="Anuluj!gtk-no:1" --text="Usuwanie plików .part"
	fi
	rm -f $res  # rm temp file
	exit        # exit here
}

# ------------------
function download_format()
# ------------------
{
    FILENAME="$(youtube-dl --get-filename "$1")"   # Get filename
    YTEMP="$1"                                     # Temp variable
    format_selection                               # Start format selection dialog
}

# ------------------
check_version()
# ------------------
{
	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
		yad --text="Can't connect to youtube-dl server site\nMake sure the internet connection is up and active" \
		--borders=10 --form --button="Ok!gtk-ok:0" \
		--center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE"
                main
        fi
	ytdlcv=$(youtube-dl --version)
	ytdllv=$(wget -O- -q "https://rg3.github.io/youtube-dl/update/LATEST_VERSION")
    if [[ "$ytdlcv" == "$ytdllv" ]]; then
	yad --text="Zainstalowana wersja youtube-dl - <b>$ytdlcv</b>\nDostępna wersja youtube-dl - <b>$ytdllv</b>\n\nyoutube-dl jest aktualne" \
	--borders=10 --form --button="Ok!gtk-ok:0" \
	--center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE"
    else
	yad --text="Zainstalowana wersja youtube-dl - <b>$ytdlcv</b>\nDostępna wersja youtube-dl - <b>$ytdllv</b>\n\nDostępna jest aktualizacja youtube-dl" \
	--borders=10 --form --button="Ok!gtk-ok:0" \
	--center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE"
    fi
}

# ------------------
dialog()
# ------------------
{
# Dialogs
	if [[ "$MODE" = "0" ]]; then
		OIFS=$IFS # save Internal Field Separator
		IFS=$'\n' # separator is "\n" in returned choices
		c=0
		YADFIELD=()
		while [[ ${c} -lt $FIELDS ]];do
			 c=$(($c+1))
			 YADFIELD+=($(echo "--field=<b>Adres YouTube\:</b>          ${c}:NORM"; echo ""))    # Store yad form fields in an array
		done
		ENTRY="$(yad --form --columns=1 --window-icon "$ICON" --center \
		   --borders=10 --title "$TITLE" --image "$IMAGE" --image-on-top \
		   --text "<b>Wybierz katalog docelowy\n i wklej adres(y) w odpowiednie pola</b>" \
		   --button="Przełącz GUI!reload:2" $(if hash wget &>/dev/null;then echo "--button=youtube-dl:3";fi) \
		   --button="Wyjdź!gtk-cancel:1" --button="Pobierz!gtk-ok:0" \
		   --field="Katalog pobranych plików:DIR" "$HOME/Pobrane" \
		   --field="Opcje pobierania:CB" "Tylko Audio (mp3)!Video (22/18/17)" \
		   --field="Jednoczesne pobieranie:NUM" "$SIMULTANEOUS!1..5!1" \
		   ${YADFIELD[@]} \
			)"
		RET=$?
		IFS=$OIFS # reset IFS back to default
		case "$RET" in
			0) # Continue
			;;
			1) # Canceled
				exit
			;;
			2)
				MODE=1
				dialog
			;;
			3)
				check_version
				main
			;;
			*)
				exit
			;;
	   esac
	elif [[ "$MODE" = "1" ]]; then
		ENTRY="$(yad --form --columns=1 --window-icon "$ICON" --center \
		   --borders=10 --title "$TITLE" --image "$IMAGE" --image-on-top \
		   --text "<b>Wybierz katalog docelowy\n i wklej adres w odpowiednie pole</b>" \
		   --button="Przełącz GUI!reload:2" $(if hash wget &>/dev/null;then echo "--button=youtube-dl:3";fi) \
		   --button="Wyjdź!gtk-cancel:1" --button="Pobierz!gtk-ok:0" \
		   --field="Katalog pobranych plików:DIR" "$HOME/Pobrane" \
		   --field="Opcje pobierania:CB" "Własne!Tylko Audio (mp3)!Video (22/18/17)" \
		   --field="Jednoczesne pobieranie:NUM" "1!1..1!1" \
		   --field="<b>Adres YouTube</b>:" "" \    # Only one url field for the Manual format selection
		   )"
		RET=$?
		case "$RET" in
		   0)      # Continue
		   ;;
		   1)      # Canceled
		   exit
		   ;;
		   2)
		   MODE=0
		   dialog
		   ;;
		   3)
		   	check_version
			main
		   ;;
		   *)
		   exit
		   ;;
		esac
	fi
}

# ------------------
main()
# ------------------
{
	while :; do
		dialog     # calls the main dialog
		OIFS=$IFS # save Internal Field Separator
		IFS="|"   # separator is "|" in returned choices
		i=0
		retChoice=()
		e=0
		URLIST=()
		for ret in $ENTRY;do
			retChoice[$i]="$ret"
			i=$(($i+1))                    # iterate i
			if [[ "$i" -gt 3 ]] && [[ "$ret" != "" ]];then   # get form fields if they are not empty
			   retType="${ret%%'='*}"                        # trim to the '=', TYPE position
			   TYPE[$e]="${retType##*'/'}"                   # extract type, playlist or video
			   retUrl="${ret%%'&'*}"                         # trim to the '&' character, URL position
			   URLIST[$e]="${retUrl##*'='}"                  # extract filename
			   YADBARS="$YADBARS --bar=${URLIST[$e]}:NORM"   # add bars to a yad multiprogress dialog
			   e=$(($e+1))                                   # iterate e
			fi
		done
		IFS=$OIFS # reset IFS back to default
		SAVEDIR=${retChoice[0]} # directory path
		OPTION=${retChoice[1]}
	  case $OPTION in
		"Video (22/18/17)")
		   UTUBE="-f 22/18/17"
		;;
		"Tylko Audio (mp3)")
		   UTUBE="--extract-audio --audio-format mp3 --audio-quality 0"
		;;
	  esac
		MAXDLS=${retChoice[2]}  # maximum number of simultaneous downloads

		if [[ -z $SAVEDIR ]] || [[ ${#URLIST[@]} -eq 0 ]];then
			yad --form --text="<b>Wypełnij choć jedno pole adresu\ni wybierz katalog</b>" --borders=10 \
			--center --title "$TITLE" --window-icon "$ICON" --image "$IMAGE" --button="gtk-ok:0"
		else
			break
		fi
	done
	if [[ "$MODE" = "1" ]] && [[ "$OPTION" == "Własne" ]]; then
	   if [[ "${TYPE[@]}" == "watch?v" ]];then
			for URL in ${URLIST[@]}; do
				download_format "https://www.youtube.com/watch?v=$URL" # call format selection dialog
				UTUBE="-f $FORMAT"
			done
		else
			YTEMP="${URLIST[0]}"
			list_selection
		fi
	fi
}

# ------------------
function progress()
# ------------------
{
	OIFS=$IFS # save Internal Field Separator
	IFS=" "   # separator is " " in returned choices
	COUNTER="1"
	DYNAMIC_COUNTER="1"
	PID=()
	c=0
	for URL in ${URLIST[@]}; do
		if [[ "$DYNAMIC_COUNTER" = "$MAXDLS" ]] # only download n files at a time
		  then
			  download "${TYPE[$c]}" "$URL" "$COUNTER" &     # pass TYPE, URL and COUNTER to download function
			  PID+=("$!")                                    # gets process pid
			  max="$(($COUNTER-1))"                          # -1, since start counter is 1, and arrays begin at 0
			  MAX_PID=${PID[$max]}                           # sets the variable pid from array PID
			  wait $MAX_PID                                  # wait until process with MAX_PID finishes
			  DYNAMIC_COUNTER="1"                            # reset dynamic counter
		  else
			  download "${TYPE[$c]}" "$URL" "$COUNTER" &     # pass TYPE, URL and counter number to download function
			  PID+=("$!")
			  DYNAMIC_COUNTER="$(($DYNAMIC_COUNTER+1))"      # iterate dinamic counter
		fi
		c=$(($c+1))                                          # iterate TYPE counter
		COUNTER="$[$COUNTER+1]"                              # iterate counter
	done | yad --multi-progress $YADBARS --title "$TITLE" --button="Anuluj i wyczyść!gtk-close:1" --button="Anuluj!gtk-close:0" \
			   --text "$TEXT" --center --window-icon "$ICON" --image "$IMAGE" --image-on-top --auto-close
	if (( $? == 1 ));then                 # Download canceled, so clean up
		for pid in ${PID[@]};do
			kill $pid &>/dev/null         # Kills any running download process
		done
		for url in ${URLIST[@]}; do
			rm "$(find "$SAVEDIR" -type f -name "*-$url.*" | grep part)" &>/dev/null   # Finds & removes the part file
		done
		notify-send -t 3000 --icon "dialog-info" "Anulowano pobieranie"
		exit
	fi
	IFS=$OIFS # reset IFS back to default
}

# ***********************
# END FUNCTIONS
# ***********************


# ***********************
# MAIN
# ***********************

main     # Calls the main loop
progress # Starts the download

# ***********************
# END MAIN
# ***********************
