#!/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 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"> You Tube ' # Set GUI variables up TITLE="YAD Pobieracz YouTube" # dialog title # Progress dialog text TEXT="Pobieranie ... 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 - $ytdlcv\nDostępna wersja youtube-dl - $ytdllv\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 - $ytdlcv\nDostępna wersja youtube-dl - $ytdllv\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=Adres YouTube\: ${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 "Wybierz katalog docelowy\n i wklej adres(y) w odpowiednie pola" \ --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 "Wybierz katalog docelowy\n i wklej adres w odpowiednie pole" \ --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="Adres YouTube:" "" \ # 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="Wypełnij choć jedno pole adresu\ni wybierz katalog" --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 # ***********************