#!/data/data/com.termux/files/usr/bin/env bash
SELF_SOURCE="true"
set -a
_assert_regex(){
declare pattern="${1-}" string="${2-}"
if [[ $string =~ $pattern ]];then
return 0
else
return 1
fi
}
_count(){
mapfile -tn 0 lines
printf '%s\n' "${#lines[@]}"
}
_epoch(){
printf '%(%s)T\n' "-1"
}
_required_column_size(){
shopt -s checkwinsize&&(:&&:)
if [[ $COLUMNS -gt 45 ]];then
trap 'shopt -s checkwinsize; (:;:)' SIGWINCH
return 0
else
return 1
fi
}
_set_value(){
case "${1:?}" in
d|direct)export "${2:?}=$3";;
i|indirect)export "${2:?}=${!3}";;
*)return 1
esac
}
_trim(){
declare char="$1" str="$2" var="$3"
if [[ -n $var ]];then
_set_value d "$var" "${str//$char/}"
else
printf "%s" "${str//$char/}"
fi
}
_auto_update(){
export COMMAND_NAME INSTALL_PATH TYPE TYPE_VALUE REPO LAST_UPDATE_TIME AUTO_UPDATE_INTERVAL
command -v "$COMMAND_NAME" 1>/dev/null&&if [ -n "${REPO:+${COMMAND_NAME:+${INSTALL_PATH:+${TYPE:+$TYPE_VALUE}}}}" ];then
current_time="$(_epoch)"
[ "$((LAST_UPDATE_TIME+AUTO_UPDATE_INTERVAL))" -lt "$(_epoch)" ]&&_update update
_update_value LAST_UPDATE_TIME "$current_time"
fi
return 0
}
_update(){
job_update="${1:-update}"
[ "${GLOBAL_INSTALL-}" = true ]&&! [ "$(id -u)" = 0 ]&&printf "%s\n" "Error: Need root access to update."&&return 0
[ "$job_update" = uninstall ]&&job_uninstall="--uninstall"
_print_center "justify" "Fetching $job_update script.." "-"
repo_update="${REPO:-akianonymus/gdrive-downloader}" type_value_update="${TYPE_VALUE:-latest}" cmd_update="${COMMAND_NAME:-gupload}" path_update="${INSTALL_PATH:-$HOME/.gdrive-downloader/bin}"
{ [ "${TYPE-}" != branch ]&&type_value_update="$(_get_latest_sha release "$type_value_update" "$repo_update")";}||:
if script_update="$(curl --compressed -Ls "https://github.com/$repo_update/raw/$type_value_update/install.sh")";then
_clear_line 1
printf "%s\n" "$script_update"|sh -n||{
printf "%s\n" "Install script downloaded but malformed, try again and if the issue persists open an issue on github."
return 1
}
printf "%s\n" "$script_update"|sh -s -- ${job_uninstall-} --skip-internet-check --cmd "$cmd_update" --path "$path_update"
current_time="$(date +'%s')"
[ -z "$job_uninstall" ]&&_update_value LAST_UPDATE_TIME "$current_time"
else
_clear_line 1
"${QUIET:-_print_center}" "justify" "Error: Cannot download" " $job_update script." "=" 1>&2
return 1
fi
return 0
}
_update_value(){
command_path="${INSTALL_PATH:?}/${COMMAND_NAME:?}"
value_name="${1:?}" value="${2-}"
script_without_value_and_shebang="$(grep -v "$value_name=\".*\".* # added values" -- "$command_path"|sed 1d)"
new_script="$(sed -n 1p -- "$command_path"
printf "%s\n" "$value_name=\"$value\" # added values"
printf "%s\n" "$script_without_value_and_shebang")"
printf "%s\n" "$new_script"|"${INSTALLATION:-bash}" -n||{
printf "%s\n" "Update downloaded but malformed, try again and if the issue persists open an issue on github."
return 1
}
chmod u+w -- "$command_path"&&printf "%s\n" "$new_script" >|"$command_path"&&chmod "a-w-r-x,${PERM_MODE:-u}+r+x" -- "$command_path"
return 0
}
_is_fd_open(){
for fd in ${1:?};do
if ! { true >&"$fd";} 2<>/dev/null;then
printf "%s\n" "Error: fd $fd not open."
return 1
fi
done
}
_parser_add_help(){
_PARSER_ALL_HELP="$_PARSER_ALL_HELP
${__PARSER_BAR-}
${1-}" 2>|/dev/null
}
_parser_check_arguments(){
nargs_parser_check_arguments="$((${1:?_parser_check_arguments}))"
num_parser_check_arguments=$(($#-2))
[ "$num_parser_check_arguments" -lt "$nargs_parser_check_arguments" ]&&{
printf "%s\n" "${0##*/}: $2: flag requires $nargs_parser_check_arguments argument."
printf "\n%s\n" "Help:"
printf "%s\n" "$(_usage "$2")"
exit 1
}
return 0
}
_flag_exists(){
tmp_flag_exists="" option_flag_exists=""
_flag_help "${1:?}" tmp_flag_exists option_flag_exists
[ -z "$tmp_flag_exists" ]&&return 1
_set_value d "${2:?}" "$option_flag_exists"
}
_flag_help(){
flag_flag_help=""
_trim "-" "${1:?_flag_help}" flag_flag_help
_set_value i "${2:?_flag_help}" "_parser__help_$flag_flag_help"
_set_value d "${3:-_}" "$flag_flag_help"
}
_parse_arguments(){
__NEWLINE="
"
_parse_support_ansi_escapes(){
case "$TERM" in
xterm*|rxvt*|urxvt*|linux*|vt*|screen*){ [ -t 2 ]&&return 0;}||return 1;;
*):
esac
{ [ -t 2 ]&&return 0;}||return 1
}
_parser_required_column_size(){
COLUMNS="$({ command -v bash 1>|/dev/null&&bash -c 'shopt -s checkwinsize && (: && :); printf "%s\n" "${COLUMNS}" 2>&1';}||{ command -v zsh 1>|/dev/null&&zsh -c 'printf "%s\n" "${COLUMNS}"';}||{ command -v stty 1>|/dev/null&&_tmp="$(stty size)"&&printf "%s\n" "${_tmp##* }";}||{ command -v tput 1>|/dev/null&&tput cols;})"||:
[ "$((COLUMNS))" -gt 45 ]&&return 0
}
_parse_support_ansi_escapes&&_parser_required_column_size&&__PARSER_BAR="$(\
filler='' \
symbol='_'
i=1&&while [ "$i" -le "$COLUMNS" ];do
filler="$filler$symbol"&&i="$((i+1))"
done
printf "%s\n" "$filler")"
__PARSER_BAR="${__PARSER_BAR:+$__PARSER_BAR$__NEWLINE}"
unset _PARSER_ALL_HELP _PARSER_ARGS_SHIFT _PARSER_PREPROCESS_FUNCTION
unset _PARSER_FLAGS _PARSER_CURRENT_FLAGS _PARSER_CURRENT_NARGS _PARSER_CURRENT_ARGS _PARSER_CURRENT_ARGS_TYPE
"${1:?_parse_arguments - 1: Missing funtion name to setup flags}"||return 1
shift 2>|/dev/null
_parser_run_preprocess||return 1
while [ "$#" -gt 0 ];do
case "$1" in
''):;;
--)shift
while [ "$#" -gt 0 ];do
_parser_process_input "$@"||return 1
shift
done
;;
-*)\
flag_parse_arguments=""
if _flag_exists "$1" flag_parse_arguments;then
"_parser_process_$flag_parse_arguments" "$@"||return 1
else
printf "%s\n\n" "${0##*/}: $1: Unknown option"
_short_help
fi
;;
*)_parser_process_input "$@"||return 1
esac
_PARSER_ARGS_SHIFT="$((_PARSER_ARGS_SHIFT+1))"
shift "$_PARSER_ARGS_SHIFT"
_PARSER_ARGS_SHIFT="0"
done
return 0
}
_parser_setup_flag(){
_PARSER_CURRENT_FLAGS="" tmp_parser_setup_flag=""
_PARSER_FLAGS="${1:?_parser_setup_flag}"
for f in $_PARSER_FLAGS;do
_trim "-" "$f" tmp_parser_setup_flag
_PARSER_CURRENT_FLAGS="$_PARSER_CURRENT_FLAGS $tmp_parser_setup_flag"
done
_PARSER_CURRENT_NARGS="${2:?_parser_setup_flag}"
_PARSER_CURRENT_ARGS_TYPE="$3"
_PARSER_CURRENT_ARGS="$4"
}
_parser_setup_flag_help(){
flags_parser_setup_flag_help="${_PARSER_CURRENT_FLAGS:?_parser_setup_flag_help}"
nargs_parser_setup_flag_help="${_PARSER_CURRENT_NARGS:?_parser_setup_flag_help}"
unset start_parser_setup_flag_help \
help_parser_setup_flag_help \
arg_parser_setup_flag_help \
all_parser_setup_flag_help
while IFS= read -r line <&4;do
help_parser_setup_flag_help="$help_parser_setup_flag_help
        $line"
done 4<<EOF
${1:?_parser_setup_flag_help}
EOF
for f in ${_PARSER_FLAGS:?_parser_setup_flag_help};do
start_parser_setup_flag_help="${start_parser_setup_flag_help:+$start_parser_setup_flag_help | }$f"
done
if ! [ "$nargs_parser_setup_flag_help" = 0 ];then
arg_parser_setup_flag_help="\"${_PARSER_CURRENT_ARGS:?_parser_setup_flag_help}\""
if [ "$_PARSER_CURRENT_ARGS_TYPE" = optional ];then
arg_parser_setup_flag_help="$arg_parser_setup_flag_help [ Optional ]"
else
arg_parser_setup_flag_help="$arg_parser_setup_flag_help [ Required ]"
fi
fi
start_parser_setup_flag_help="    $start_parser_setup_flag_help $arg_parser_setup_flag_help"
all_setup_help_flag="$start_parser_setup_flag_help${__NEWLINE:?}$help_parser_setup_flag_help"
for f in $flags_parser_setup_flag_help;do
_set_value d "_parser__help_$f" "$all_setup_help_flag"
done
[ "$_PARSER_FLAGS" = input ]&&return 0
_PARSER_ALL_HELP="$_PARSER_ALL_HELP
${__PARSER_BAR-}
$all_setup_help_flag" 2>|/dev/null
}
_parser_setup_flag_preprocess(){
_is_fd_open 4||return 1
unset fn_parser_setup_flag_preprocess
while IFS= read -r line <&4;do
fn_parser_setup_flag_preprocess="$fn_parser_setup_flag_preprocess
$line"
done
_PARSER_PREPROCESS_FUNCTION="$_PARSER_PREPROCESS_FUNCTION
$fn_parser_setup_flag_preprocess"
}
_parser_setup_flag_process(){
_is_fd_open 4||return 1
unset fn_parser_setup_flag_process
if [ "${_PARSER_CURRENT_NARGS:?_parser_setup_flag_process}" -gt 0 ]&&! [ "$_PARSER_CURRENT_ARGS_TYPE" = optional ];then
fn_parser_setup_flag_process="_parser_check_arguments ${_PARSER_CURRENT_NARGS:?_parser_setup_flag_process} \"\${@}\""
fi
while IFS= read -r line <&4;do
fn_parser_setup_flag_process="$fn_parser_setup_flag_process
$line"
done
for f in ${_PARSER_CURRENT_FLAGS:?_parser_setup_flag_process};do
eval "_parser_process_$f() { $fn_parser_setup_flag_process ; }"
done
}
_parser_run_preprocess(){
eval "_parser_preprocess_setup() { ${_PARSER_PREPROCESS_FUNCTION:-:} ; }"&&_parser_preprocess_setup
}
_parser_shift(){
export _PARSER_ARGS_SHIFT="${1:-1}"
}
_short_help(){
printf "No valid arguments provided, use -h/--help flag to see usage.\n"
exit 0
}
_set_value(){
case "${1:?}" in
d|direct)export "${2:?}=$3";;
i|indirect)eval export "$2"=\"\$"$3"\";;
*)return 1
esac
}
_trim(){
char_trim="$1" str_trim="$2" var_trim="$3"
set -f
old_ifs="$IFS"
IFS="$char_trim"
set -- $str_trim
IFS=
if [ -n "$var_trim" ];then
_set_value d "$var_trim" "$*"
else
printf "%s" "$*"
fi
IFS="$old_ifs"
set +f
}
_parser_setup_flags(){
_parser_add_help "
The script can be used to download file/directory from google drive.

Usage: ${0##*/} [options.. ] <file_[url|id]> or <folder[url|id]>

Options:"
_parser_setup_flag "input" 0
_parser_setup_flag_help \
"Drive urls or id to process."
_parser_setup_flag_preprocess 4<<'EOF'
unset TOTAL_INPUTS INPUT_ID
EOF
_parser_setup_flag_process 4<<'EOF'
# set ID_INPUT_NUM to the input, where num is rank of input
id_parse_arguments=""
_extract_id "${1}" id_parse_arguments 

if [ -n "${id_parse_arguments}" ]; then
    # this works well in place of arrays
    _set_value d "INPUT_ID_$((TOTAL_INPUTS += 1))" "${id_parse_arguments}"
fi
EOF
_parser_setup_flag "-am --alternate-method" 0
_parser_setup_flag_help \
"Use this flag to use alternate method of downloading.

In default mode, all the folder information if fetched recursively and then download is started.

In alternate mode, downloading is done one folder at a time."
_parser_setup_flag_preprocess 4<<'EOF'
export DOWNLOAD_METHOD="alt"
EOF
_parser_setup_flag_process 4<<'EOF'
export DOWNLOAD_METHOD="noalt"
EOF
_parser_setup_flag "-aria" 0
_parser_setup_flag_help \
"Use aria2c to download. To use custom flags for aria, see --aria-flags option."
_parser_setup_flag_process 4<<'EOF'
if ! command -v aria2c 1>|/dev/null ; then
    printf "%s\n" "Error: aria2c not installed."
    return 1
fi
export DOWNLOADER="aria2c"
EOF
_parser_setup_flag "--aria-flags" 1 required 'flags'
_parser_setup_flag_help \
'Same as -aria flag but requires argument.

To give custom flags as argument, do
    e.g: --aria-flags "-s 10 -x 10"

Note 1: aria2c can only resume google drive downloads if "-k/--key" or "-o/--oauth" option is used.

Note 2: aria split downloading will not work in normal mode ( without "-k" or "-o" flag ) because it cannot get the remote server size. Same for any other feature which uses remote server size.

Note 3: By above notes, conclusion is, aria is basically same as curl in normal mode, so it is recommended to be used only with "--key" and "--oauth" flag.'
_parser_setup_flag_preprocess 4<<'EOF'
unset ARIA_FLAGS 
EOF
_parser_setup_flag_process 4<<'EOF'
if ! command -v aria2c 1>|/dev/null ; then
    printf "%s\n" "Error: aria2c not installed."
    return 1
fi
export DOWNLOADER="aria2c"
[ "${1}" = "--aria-flags" ] && {
    ARIA_FLAGS=" ${ARIA_FLAGS} ${2} " && _parser_shift 
}
EOF
_parser_setup_flag "-o --oauth" 0
_parser_setup_flag_help \
"Use this flag to trigger oauth authentication.

Note: If both --oauth and --key flag is used, --oauth flag is preferred."
_parser_setup_flag_preprocess 4<<'EOF'
unset OAUTH_ENABLED ACCOUNT_NAME \
    ROOT_FOLDER ROOT_FOLDER_NAME CLIENT_ID CLIENT_SECRET REFRESH_TOKEN ACCESS_TOKEN ACCESS_TOKEN_EXPIRY INITIAL_ACCESS_TOKEN REFETCH_REFRESH_TOKEN
EOF
_parser_setup_flag_process 4<<'EOF'
export OAUTH_ENABLED="true"
EOF
_parser_setup_flag "--oauth-refetch-refresh-token" 0
_parser_setup_flag_help \
"Use this flag to trigger refetching of refresh token if existing refresh token is expired."
_parser_setup_flag_preprocess 4<<'EOF'
unset OAUTH_ENABLED ACCOUNT_NAME \
    ROOT_FOLDER ROOT_FOLDER_NAME CLIENT_ID CLIENT_SECRET REFRESH_TOKEN ACCESS_TOKEN ACCESS_TOKEN_EXPIRY INITIAL_ACCESS_TOKEN REFETCH_REFRESH_TOKEN
EOF
_parser_setup_flag_process 4<<'EOF'
export OAUTH_ENABLED="true" REFETCH_REFRESH_TOKEN="true"
EOF
_parser_setup_flag "-a --account" 1 required "account name"
_parser_setup_flag_help \
"Use a different account than the default one.

To change the default account name, use this format, -a/--account default=account_name"
_parser_setup_flag_preprocess 4<<'EOF'
unset OAUTH_ENABLED ACCOUNT_NAME ACCOUNT_ONLY_RUN CUSTOM_ACCOUNT_NAME UPDATE_DEFAULT_ACCOUNT
EOF
_parser_setup_flag_process 4<<'EOF'
export OAUTH_ENABLED="true" CUSTOM_ACCOUNT_NAME="${2##default=}"
[ -z "${2##default=*}" ] && export UPDATE_DEFAULT_ACCOUNT="_update_config"
_parser_shift
EOF
_parser_setup_flag "-la --list-accounts" 0
_parser_setup_flag_help \
"Print all configured accounts in the config files."
_parser_setup_flag_preprocess 4<<'EOF'
unset LIST_ACCOUNTS
EOF
_parser_setup_flag_process 4<<'EOF'
export LIST_ACCOUNTS="true"
EOF
_parser_setup_flag "-ca --create-account" 1 required "account name"
_parser_setup_flag_help \
"To create a new account with the given name if does not already exists."
_parser_setup_flag_preprocess 4<<'EOF'
unset OAUTH_ENABLED NEW_ACCOUNT_NAME
EOF
_parser_setup_flag_process 4<<'EOF'
export OAUTH_ENABLED="true"
export NEW_ACCOUNT_NAME="${2}" && _parser_shift 
EOF
_parser_setup_flag "-da --delete-account" 1 required "account name"
_parser_setup_flag_help \
"To delete an account information from config file."
_parser_setup_flag_preprocess 4<<'EOF'
unset DELETE_ACCOUNT_NAME
EOF
_parser_setup_flag_process 4<<'EOF'
export DELETE_ACCOUNT_NAME="${2}" && _parser_shift 
EOF
_parser_setup_flag "-k --key" 1 optional "API KEY"
_parser_setup_flag_help \
"To download with api key. If api key is not specified, then the predefined api key will be used.

To save your api key in config file, use gdl --key default=your api key.

API key will be saved in '$HOME/.gdl.conf' and will be used from now on.

Note: If both --key and --key oauth is used, --oauth flag is preferred."
_parser_setup_flag_preprocess 4<<'EOF'
unset API_KEY_DOWNLOAD UPDATE_DEFAULT_API_KEY
export API_KEY="AIzaSyD2dHsZJ9b4OXuy5B_owiL8W18NaNOM8tk"
EOF
_parser_setup_flag_process 4<<'EOF'
export API_KEY_DOWNLOAD="true"
_API_KEY="${2##default=}"
# https://github.com/l4yton/RegHex#Google-Drive-API-Key
regex="AIza[0-9A-Za-z_-]{35}"
if [ -n "${_API_KEY}" ] && _assert_regex "${regex}" "${_API_KEY}"; then
    export API_KEY="${_API_KEY}" && _parser_shift 
    [ -z "${2##default=*}" ] && UPDATE_DEFAULT_API_KEY="_update_config"
fi
EOF
_parser_setup_flag "-c --config" 1 required "config file path"
_parser_setup_flag_help \
"Override default config file with custom config file.

Default: '$HOME/.gdl.conf'"
_parser_setup_flag_process 4<<'EOF'
CONFIG="${2}" && _parser_shift 
EOF
_parser_setup_flag "-d --directory" 1 required "foldername"
_parser_setup_flag_help \
"To download given input in custom directory."
_parser_setup_flag_preprocess 4<<'EOF'
unset FOLDERNAME
EOF
_parser_setup_flag_process 4<<'EOF'
export FOLDERNAME="${2}" && _parser_shift 
EOF
_parser_setup_flag "-df --document-format" 1 required "document type"
_parser_setup_flag_help \
"Can be used for documents to be downloaded in different format like docx, pdf, zip, epub, etc.

Available formats are: docx, odt, rtf, pdf, txt, zip, epub, xlsx, ods, csv, tsv, pptx, odp, jpg, png, svg, json"
_parser_setup_flag_preprocess 4<<'EOF'
DOCUMENT_FORMAT=""
DOCUMENT_FORMAT_ESCAPED=""
EOF
_parser_setup_flag_process 4<<'EOF'
DOCUMENT_FORMAT="${2}"
DOCUMENT_FORMAT_ESCAPED="${_get_export_mime "${DOCUMENT_FORMAT}"}"
if [ -z "${DOCUMENT_FORMAT_ESCAPED}" ]; then
    printf "\nError: Wrong document format.\nAvailable formats are: rtf, odt, pdf, epub, zip, docx, txt, etc. See help" && return 1
fi
export DOCUMENT_FORMAT DOCUMENT_FORMAT_ESCAPED && _parser_shift 
EOF
_parser_setup_flag "-dr --dry-run" 0
_parser_setup_flag_help \
"Just check if the url can be downloaded and exit the script."
_parser_setup_flag_preprocess 4<<'EOF'
unset DRY_RUN
EOF
_parser_setup_flag_process 4<<'EOF'
export DRY_RUN="true"
EOF
_parser_setup_flag "-s --skip-subdirs" 0
_parser_setup_flag_help \
"Skip downloading of sub folders present in case of folders."
_parser_setup_flag_preprocess 4<<'EOF'
unset SKIP_SUBDIRS
EOF
_parser_setup_flag_process 4<<'EOF'
export SKIP_SUBDIRS="true"
EOF
_parser_setup_flag "-p --parallel" 1 required "num of parallel downloads"
_parser_setup_flag_help \
"Download multiple files in parallel."
_parser_setup_flag_preprocess 4<<'EOF'
unset NO_OF_PARALLEL_JOBS PARALLEL_DOWNLOAD
EOF
_parser_setup_flag_process 4<<'EOF'
if [ "${2}" -gt 0 ] 2>| /dev/null 1>&2; then
    export NO_OF_PARALLEL_JOBS="${2}"
else
    printf "\nError: -p/--parallel accepts values between 1 to 10.\n"
    return 1
fi
export PARALLEL_DOWNLOAD="parallel"
_parser_shift
EOF
_parser_setup_flag "--proxy" 1 required "http://user:password@host:port"
_parser_setup_flag_help \
"Specify a proxy to use, should be in the format accepted by curl --proxy and aria2c --all-proxy flag."
_parser_setup_flag_preprocess 4<<'EOF'
unset PROXY
export ARIA_PROXY_FLAG="--all-proxy" CURL_PROXY_FLAG="--proxy"
EOF
_parser_setup_flag_process 4<<'EOF'
export PROXY="${2}" && _parser_shift 
EOF
_parser_setup_flag "--speed" 1 required "speed"
_parser_setup_flag_help \
"Limit the download speed, supported formats: 1K and 1M"
_parser_setup_flag_preprocess 4<<'EOF'
unset SPEED_LIMIT
export CURL_SPEED_LIMIT_FLAG="--limit-rate" ARIA_SPEED_LIMIT_FLAG="--max-download-limit"
EOF
_parser_setup_flag_process 4<<'EOF'
regex='^([0-9]+)([k,K]|[m,M])+$'
if _assert_regex "${regex}" "${2}"; then
    export SPEED_LIMIT="${2}" && _parser_shift 
else
    printf "Error: Wrong speed limit format, supported formats: 1K and 1M.\n" 1>&2
    return 1
fi
EOF
_parser_setup_flag "-ua --user-agent" 1 required "user agent string"
_parser_setup_flag_help \
"Specify custom user agent."
_parser_setup_flag_preprocess 4<<'EOF'
unset USER_AGENT
export USER_AGENT_FLAG="--user-agent" # common for both curl and aria2c
EOF
_parser_setup_flag_process 4<<'EOF'
export USER_AGENT="${2}" && shift
EOF
_parser_setup_flag "-R --retry" 1 required "num of retries"
_parser_setup_flag_help \
"Retry the file upload if it fails, postive integer as argument. Currently only for file uploads."
_parser_setup_flag_preprocess 4<<'EOF'
unset RETRY
EOF
_parser_setup_flag_process 4<<'EOF'
if [ "$((2))" -gt 0 ] 2>| /dev/null 1>&2; then
    export RETRY="${2}" && _parser_shift 
else
    printf "Error: -R/--retry only takes positive integers as arguments, min = 1, max = infinity.\n"
    return 1
fi
EOF
_parser_setup_flag "-in --include" 1 required "pattern"
_parser_setup_flag_help \
"Only download the files which contain the given pattern - Applicable for folder downloads.

e.g: ${0##*/} local_folder --include 1, will only include with files with pattern 1 in the name. Regex can be used which works with grep -E command."
_parser_setup_flag_preprocess 4<<'EOF'
unset INCLUDE_FILES 
EOF
_parser_setup_flag_process 4<<'EOF'
export INCLUDE_FILES="${INCLUDE_FILES:+${INCLUDE_FILES}|}${2}" && _parser_shift 
EOF
_parser_setup_flag "-ex --exclude" 1 required "pattern"
_parser_setup_flag_help \
"Only download the files which does not contain the given pattern - Applicable for folder downloads.

e.g: ${0##*/} local_folder --exclude 1, will only include with files with pattern 1 not present in the name. Regex can be used which works with grep -E command."
_parser_setup_flag_preprocess 4<<'EOF'
unset EXCLUDE_FILES
EOF
_parser_setup_flag_process 4<<'EOF'
export EXCLUDE_FILES="${EXCLUDE_FILES:+${EXCLUDE_FILES}|}${2}" && _parser_shift 
EOF
_parser_setup_flag "-l --log" 1 required "file to save info"
_parser_setup_flag_help \
"Save downloaded files info to the given filename."
_parser_setup_flag_preprocess 4<<'EOF'
unset LOG_FILE_ID
EOF
_parser_setup_flag_process 4<<'EOF'
export LOG_FILE_ID="${2}" && _parser_shift 
EOF
_parser_setup_flag "-q --quiet" 0
_parser_setup_flag_help \
"Supress the normal output, only show success/error upload messages for files, and one extra line at the beginning for folder showing no. of files and sub folders."
_parser_setup_flag_preprocess 4<<'EOF'
unset QUIET
EOF
_parser_setup_flag_process 4<<'EOF'
export QUIET="_print_center_quiet"
EOF
_parser_setup_flag "--verbose" 0
_parser_setup_flag_help \
"Display detailed message (only for non-parallel uploads)."
_parser_setup_flag_preprocess 4<<'EOF'
unset VERBOSE
EOF
_parser_setup_flag_process 4<<'EOF'
export VERBOSE="true" CURL_PROGRESS=""
EOF
_parser_setup_flag "--skip-internet-check" 0
_parser_setup_flag_help \
"Do not check for internet connection, recommended to use in sync jobs."
_parser_setup_flag_preprocess 4<<'EOF'
unset SKIP_INTERNET_CHECK
EOF
_parser_setup_flag_process 4<<'EOF'
SKIP_INTERNET_CHECK=":"
EOF
_parser_setup_flag "-V --version --info" 0
_parser_setup_flag_help \
"Show detailed info, only if script is installed system wide."
_parser_setup_flag_preprocess 4<<'EOF'
###################################################
# Print info if installed
###################################################
_version_info() {
    export COMMAND_NAME REPO INSTALL_PATH TYPE TYPE_VALUE
    if command -v "${COMMAND_NAME}" 1> /dev/null && [ -n "${REPO:+${COMMAND_NAME:+${INSTALL_PATH:+${TYPE:+${TYPE_VALUE}}}}}" ]; then
        for i in REPO INSTALL_PATH INSTALLATION TYPE TYPE_VALUE LATEST_INSTALLED_SHA CONFIG; do
            value_version_info=""
            _set_value i value_version_info "${i}"
            printf "%s\n" "${i}=${value_version_info}"
        done | sed -e "s/=/: /g"
    else
        printf "%s\n" "gdrive-downloader is not installed system wide."
    fi
    exit 0
}
EOF
_parser_setup_flag_process 4<<'EOF'
_version_info
EOF
_parser_setup_flag "-D --debug" 0
_parser_setup_flag_help \
"Display script command trace."
_parser_setup_flag_preprocess 4<<'EOF'
unset DEBUG
EOF
_parser_setup_flag_process 4<<'EOF'
export DEBUG="true"
EOF
_parser_setup_flag "-h --help" 1 optional "flag name"
_parser_setup_flag_help \
"Print help for all flags and basic usage instructions.

To see help for a specific flag, --help flag_name ( with or without dashes )
    e.g: ${0##*/} --help aria
Can also specify multiple flag names
    e.g: ${0##*/} --help config list-account"
_parser_setup_flag_preprocess 4<<'EOF'
###################################################
# 1st arg - can be flag name
# if 1st arg given, print specific flag help
# otherwise print full help
###################################################
_usage() {
    [ -n "${1}" ] && {
        for flag_usage in "${@}"; do
            help_usage_usage=""
            _flag_help "${flag_usage}" help_usage_usage

            if [ -z "${help_usage_usage}" ]; then
                printf "%s\n" "Error: No help found for ${flag_usage}"
            else
                printf "%s\n%s\n%s\n" "${__PARSER_BAR}" "${help_usage_usage}" "${__PARSER_BAR}"
            fi
        done
        exit 0
    }

    printf "%s\n" "${_PARSER_ALL_HELP}"
    exit 0
}
EOF
_parser_setup_flag_process 4<<'EOF'
shift 1 && _usage "${@}"
EOF
[ "${GDL_INSTALLED_WITH-}" = script ]&&{
_parser_setup_flag "-u --update" 0
_parser_setup_flag_help \
"Update the installed script in your system."
_parser_setup_flag_process 4<<'EOF'
_check_debug && _update && { exit 0 || exit 1; }
EOF
_parser_setup_flag "--uninstall" 0
_parser_setup_flag_help \
"Uninstall script, remove related files."
_parser_setup_flag_process 4<<'EOF'
_check_debug && _update uninstall && { exit 0 || exit 1; }
EOF
}
return 0
}
_account_name_valid(){
name_account_name_valid="${1:?}" account_name_regex_account_name_valid='^([A-Za-z0-9_])+$'
_assert_regex "$account_name_regex_account_name_valid" "$name_account_name_valid"||return 1
return 0
}
_account_exists(){
name_account_exists="${1-}" client_id_account_exists="" client_secret_account_exists="" refresh_token_account_exists=""
_account_name_valid "$name_account_exists"||return 1
_set_value indirect client_id_account_exists "ACCOUNT_${name_account_exists}_CLIENT_ID"
_set_value indirect client_secret_account_exists "ACCOUNT_${name_account_exists}_CLIENT_SECRET"
_set_value indirect refresh_token_account_exists "ACCOUNT_${name_account_exists}_REFRESH_TOKEN"
[ -z "${client_id_account_exists:+${client_secret_account_exists:+$refresh_token_account_exists}}" ]&&return 1
return 0
}
_all_accounts(){
export CONFIG QUIET
{ _reload_config&&_handle_old_config;}||return 1
COUNT=0
while read -r account <&4&&[ -n "$account" ];do
_account_exists "$account"&&{ [ "$COUNT" = 0 ]&&"${QUIET:-_print_center}" "normal" " All available accounts. " "="||:;}&&printf "%b" "$((COUNT+=1)). $account \n"&&_set_value direct "ACC_${COUNT}_ACC" "$account"
done 4<<EOF
$(grep -oE '^ACCOUNT_.*_CLIENT_ID' -- "$CONFIG"|sed -e "s/ACCOUNT_//g" -e "s/_CLIENT_ID//g")
EOF
{ [ "$COUNT" -le 0 ]&&"${QUIET:-_print_center}" "normal" " No accounts configured yet. " "=" 1>&2;}||printf '\n'
return 0
}
_set_new_account_name(){
export QUIET NEW_ACCOUNT_NAME
_reload_config||return 1
new_account_name_set_new_account_name="${1-}"&&unset name_valid_set_new_account_name
[ -z "$new_account_name_set_new_account_name" ]&&{
_all_accounts 2>|/dev/null
"${QUIET:-_print_center}" "normal" " New account name: " "="
"${QUIET:-_print_center}" "normal" "Info: Account names can only contain alphabets / numbers / dashes." " "&&printf '\n'
}
until [ -n "$name_valid_set_new_account_name" ];do
if [ -n "$new_account_name_set_new_account_name" ];then
if _account_name_valid "$new_account_name_set_new_account_name";then
if _account_exists "$new_account_name_set_new_account_name";then
"${QUIET:-_print_center}" "normal" " Warning: Given account ( $new_account_name_set_new_account_name ) already exists, input different name. " "-" 1>&2
unset new_account_name_set_new_account_name&&continue
else
export NEW_ACCOUNT_NAME="$new_account_name_set_new_account_name"&&name_valid_set_new_account_name="true"&&continue
fi
else
"${QUIET:-_print_center}" "normal" " Warning: Given account name ( $new_account_name_set_new_account_name ) invalid, input different name. " "-"
unset new_account_name_set_new_account_name&&continue
fi
else
[ -t 1 ]||{ "${QUIET:-_print_center}" "normal" " Error: Not running in an interactive terminal, cannot ask for new account name. " 1>&2&&return 1;}
printf -- "-> \033[?7l"
read -r new_account_name_set_new_account_name
printf '\033[?7h'
fi
_clear_line 1
done
"${QUIET:-_print_center}" "normal" " Given account name: $NEW_ACCOUNT_NAME " "="
export ACCOUNT_NAME="$NEW_ACCOUNT_NAME"
return 0
}
_delete_account(){
export CONFIG QUIET
{ _reload_config&&_handle_old_config;}||return 1
account_delete_account="${1:?Error: give account name}"&&unset regex_delete_account config_without_values_delete_account
if _account_exists "$account_delete_account";then
regex_delete_account="^ACCOUNT_${account_delete_account}_(CLIENT_ID=|CLIENT_SECRET=|REFRESH_TOKEN=|ROOT_FOLDER=|ROOT_FOLDER_NAME=|ACCESS_TOKEN=|ACCESS_TOKEN_EXPIRY=)|DEFAULT_ACCOUNT=\"$account_delete_account\""
config_without_values_delete_account="$(grep -vE "$regex_delete_account" -- "$CONFIG")"
chmod u+w -- "$CONFIG"||return 1
printf "%s\n" "$config_without_values_delete_account" >|"$CONFIG"||return 1
chmod "a-w-r-x,u+r" -- "$CONFIG"||return 1
"${QUIET:-_print_center}" "normal" " Successfully deleted account ( $account_delete_account ) from config. " "-"
else
"${QUIET:-_print_center}" "normal" " Error: Cannot delete account ( $account_delete_account ) from config. No such account exists " "-" 1>&2
fi
return 0
}
_handle_old_config(){
export CLIENT_ID CLIENT_SECRET REFRESH_TOKEN ROOT_FOLDER ROOT_FOLDER_NAME
[ -n "${CLIENT_ID:+${CLIENT_SECRET:+$REFRESH_TOKEN}}" ]&&{
account_name_handle_old_config="default" regex_check_handle_old_config config_without_values_handle_old_config count_handle_old_config
until ! _account_exists "$account_name_handle_old_config";do
account_name_handle_old_config="$account_name_handle_old_config$((count_handle_old_config+=1))"
done
regex_check_handle_old_config="^(CLIENT_ID=|CLIENT_SECRET=|REFRESH_TOKEN=|ROOT_FOLDER=|ROOT_FOLDER_NAME=|ACCESS_TOKEN=|ACCESS_TOKEN_EXPIRY=)"
config_without_values_handle_old_config="$(grep -vE "$regex_check_handle_old_config" -- "$CONFIG")"
chmod u+w -- "$CONFIG"||return 1
printf "%s\n%s\n%s\n%s\n%s\n%s\n" \
"ACCOUNT_${account_name_handle_old_config}_CLIENT_ID=\"$CLIENT_ID\"" \
"ACCOUNT_${account_name_handle_old_config}_CLIENT_SECRET=\"$CLIENT_SECRET\"" \
"ACCOUNT_${account_name_handle_old_config}_REFRESH_TOKEN=\"$REFRESH_TOKEN\"" \
"ACCOUNT_${account_name_handle_old_config}_ROOT_FOLDER=\"$ROOT_FOLDER\"" \
"ACCOUNT_${account_name_handle_old_config}_ROOT_FOLDER_NAME=\"$ROOT_FOLDER_NAME\"" \
"$config_without_values_handle_old_config" >|"$CONFIG"||return 1
chmod "a-w-r-x,u+r" -- "$CONFIG"||return 1
_reload_config||return 1
}
return 0
}
_check_credentials(){
export CONFIG CONFIG_INFO DEFAULT_ACCOUNT NEW_ACCOUNT_NAME CUSTOM_ACCOUNT_NAME QUIET COUNT
{ _reload_config&&_handle_old_config;}||return 1
ACCOUNT_NAME="$DEFAULT_ACCOUNT"
if [ -n "$NEW_ACCOUNT_NAME" ];then
_set_new_account_name "$NEW_ACCOUNT_NAME"||return 1
_check_account_credentials "$ACCOUNT_NAME"||return 1
else
if [ -n "$CUSTOM_ACCOUNT_NAME" ];then
if _account_exists "$CUSTOM_ACCOUNT_NAME";then
ACCOUNT_NAME="$CUSTOM_ACCOUNT_NAME"
else
"${QUIET:-_print_center}" "normal" " Error: No such account ( $CUSTOM_ACCOUNT_NAME ) exists. " "-"&&return 1
fi
elif [ -n "$DEFAULT_ACCOUNT" ];then
_account_exists "$DEFAULT_ACCOUNT"||{
_update_config DEFAULT_ACCOUNT "" "$CONFIG"&&unset DEFAULT_ACCOUNT ACCOUNT_NAME&&UPDATE_DEFAULT_ACCOUNT="_update_config"
}
else
UPDATE_DEFAULT_ACCOUNT="_update_config"
fi
if [ -z "$ACCOUNT_NAME" ];then
if _all_accounts 2>|/dev/null&&[ "$COUNT" -gt 0 ];then
if [ "$COUNT" -eq 1 ];then
_set_value indirect ACCOUNT_NAME "ACC_1_ACC"
else
"${QUIET:-_print_center}" "normal" " Above accounts are configured, but default one not set. " "="
if [ -t 1 ];then
"${QUIET:-_print_center}" "normal" " Choose default account: " "-"
until [ -n "$ACCOUNT_NAME" ];do
printf -- "-> \033[?7l"
read -r account_name_check_credentials
printf '\033[?7h'
if [ "$account_name_check_credentials" -gt 0 ]&&[ "$account_name_check_credentials" -le "$COUNT" ];then
_set_value indirect ACCOUNT_NAME "ACC_${COUNT}_ACC"
else
_clear_line 1
fi
done
else
printf "%s\n" "Warning: Script is not running in a terminal, choosing first account as default."
_set_value indirect ACCOUNT_NAME "ACC_1_ACC"
fi
fi
else
_set_new_account_name ""||return 1
_check_account_credentials "$ACCOUNT_NAME"||return 1
fi
fi
_check_account_credentials "$ACCOUNT_NAME"||return 1
fi
"${UPDATE_DEFAULT_ACCOUNT:-:}" DEFAULT_ACCOUNT "$ACCOUNT_NAME" "$CONFIG"
"${UPDATE_DEFAULT_CONFIG:-:}" CONFIG "$CONFIG" "$CONFIG_INFO"
[ -n "$CONTINUE_WITH_NO_INPUT" ]||_token_bg_service
return 0
}
_check_account_credentials(){
account_name_check_account_credentials="${1:?Give account name}"
{
_check_client ID "$account_name_check_account_credentials"&&_check_client SECRET "$account_name_check_account_credentials"&&_check_refresh_token "$account_name_check_account_credentials"&&_check_access_token "$account_name_check_account_credentials" check
}||return 1
return 0
}
_check_client(){
export CONFIG QUIET
type_check_client="CLIENT_${1:?Error: ID or SECRET}" account_name_check_client="${2-}"
unset type_value_check_client type_name_check_client valid_check_client client_check_client message_check_client regex_check_client
if [ "$type_check_client" = "CLIENT_ID" ];then
regex_check_client='[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com'
else
regex_check_client='[0-9A-Za-z_-]+'
fi
type_name_check_client="${account_name_check_client:+ACCOUNT_${account_name_check_client}_}$type_check_client"
_set_value indirect type_value_check_client "$type_name_check_client"
until [ -n "$type_value_check_client" ]&&[ -n "$valid_check_client" ];do
[ -n "$type_value_check_client" ]&&{
if _assert_regex "$regex_check_client" "$type_value_check_client";then
[ -n "$client_check_client" ]&&{ _update_config "$type_name_check_client" "$type_value_check_client" "$CONFIG"||return 1;}
valid_check_client="true"&&continue
else
{ [ -n "$client_check_client" ]&&message_check_client="- Try again";}||message_check_client="in config ( $CONFIG )"
"${QUIET:-_print_center}" "normal" " Invalid Client $1 $message_check_client " "-"&&unset "$type_name_check_client" client
fi
}
[ -z "$client_check_client" ]&&printf "\n"&&"${QUIET:-_print_center}" "normal" " Enter Client $1 " "-"
[ -n "$client_check_client" ]&&_clear_line 1
printf -- "-> "
read -r "${type_name_check_client?}"&&client_check_client=1
_set_value indirect type_value_check_client "$type_name_check_client"
done
_set_value direct "$type_name_check_client" "$type_value_check_client"
_set_value direct "$type_check_client" "$type_value_check_client"
return 0
}
_check_refresh_token(){
export CLIENT_ID CLIENT_SECRET QUIET CONFIG CURL_PROGRESS SCOPE REDIRECT_URI TOKEN_URL
[ -z "${CLIENT_ID:+$CLIENT_SECRET}" ]&&return 1
account_name_check_refresh_token="${1-}"
refresh_token_regex='[0-9]//[0-9A-Za-z_-]+' authorization_code_regex='[0-9]/[0-9A-Za-z_-]+'
_set_value direct refresh_token_name_check_refresh_token "${account_name_check_refresh_token:+ACCOUNT_${account_name_check_refresh_token}_}REFRESH_TOKEN"
_set_value indirect refresh_token_value_check_refresh_token "${refresh_token_name_check_refresh_token-}"
[ "${REFETCH_REFRESH_TOKEN:-false}" = "true" ]&&{
unset refresh_token_value_check_refresh_token
}
[ -n "$refresh_token_value_check_refresh_token" ]&&{
! _assert_regex "$refresh_token_regex" "$refresh_token_value_check_refresh_token"&&"${QUIET:-_print_center}" "normal" " Error: Invalid Refresh token in config file, follow below steps.. " "-"&&unset refresh_token_value_check_refresh_token
}
[ -z "$refresh_token_value_check_refresh_token" ]&&{
printf "\n"&&"${QUIET:-_print_center}" "normal" "If you have a refresh token generated, then type the token, else leave blank and press return key.." " "
printf "\n"&&"${QUIET:-_print_center}" "normal" " Refresh Token " "-"&&printf -- "-> "
read -r refresh_token_value_check_refresh_token
if [ -n "$refresh_token_value_check_refresh_token" ];then
"${QUIET:-_print_center}" "normal" " Checking refresh token.. " "-"
if _assert_regex "$refresh_token_regex" "$refresh_token_value_check_refresh_token";then
_set_value direct REFRESH_TOKEN "$refresh_token_value_check_refresh_token"
{ _check_access_token "$account_name_check_refresh_token" skip_check&&_update_config "$refresh_token_name_check_refresh_token" "$refresh_token_value_check_refresh_token" "$CONFIG"&&_clear_line 1;}||check_error_check_refresh_token=true
else
check_error_check_refresh_token=true
fi
[ -n "$check_error_check_refresh_token" ]&&"${QUIET:-_print_center}" "normal" " Error: Invalid Refresh token given, follow below steps to generate.. " "-"&&unset refresh_token_value_check_refresh_token
else
"${QUIET:-_print_center}" "normal" " No Refresh token given, follow below steps to generate.. " "-"&&unset refresh_token_value_check_refresh_token
fi
server_string_check_refresh_token='Now go back to command line..'
server_port_check_refresh_token='8079'
while :;do
: "$((server_port_check_refresh_token+=1))"
if [ "$server_port_check_refresh_token" -gt 8130 ];then
"${QUIET:-_print_center}" "normal" "Error: No open ports found ( 8080 to 8130 )." "-"
return 1
fi
{ curl -Is "http://localhost:$server_port_check_refresh_token"&&continue;}||break
done
if command -v python3 1>/dev/null&&python -V|grep -q 'Python 3';then
python3 -u <<EOF 1>"$TMPFILE.code" 2>&1&
from http.server import BaseHTTPRequestHandler, HTTPServer

class handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        if '/?code' in self.path:
            message = '$server_string_check_refresh_token'
            self.wfile.write(bytes(message, "utf8"))

with HTTPServer(('', $server_port_check_refresh_token), handler) as server:
    server.handle_request()
EOF
_tmp_server_pid="$!"
elif command -v nc 1>/dev/null;then
printf "%b" "HTTP/1.1 200 OK\nContent-Length: $(printf "%s" "$server_string_check_refresh_token"|wc -c)\n\n$server_string_check_refresh_token"|nc -l -p "$server_port_check_refresh_token" 1>"$TMPFILE.code" 2>&1&
_tmp_server_pid="$!"
else
"${QUIET:-_print_center}" "normal" " Error: neither netcat (nc) nor python3 is installed. It is required to required a http server which is used in fetching authorization code. Install and proceed." "-"
return 1
fi
code_challenge_check_refresh_token="$(_epoch)authorization_code"
[ -z "$refresh_token_value_check_refresh_token" ]&&{
printf "\n"&&"${QUIET:-_print_center}" "normal" "Visit the below URL, follow the instructions and then come back to commandline" " "
URL="https://accounts.google.com/o/oauth2/auth?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI%3A$server_port_check_refresh_token&scope=$SCOPE&response_type=code&code_challenge_method=plain&code_challenge=$code_challenge_check_refresh_token"
printf "\n%s\n" "$URL"
"${QUIET:-_print_center}" "normal" " Press enter if you have completed the process in browser" "-"
read -r _
kill "$_tmp_server_pid" 1>|/dev/null 2>&1||:
if ! authorization_code="$(grep -m1 'GET.*code.*HTTP/1.1' <"$TMPFILE.code"|sed -e 's/.*GET.*code=//' -e 's/\&.*//')"&&_assert_regex "$authorization_code_regex" "$authorization_code";then
"${QUIET:-_print_center}" "normal" " Code was not fetched properly , here is some info that maybe helpful.. " "-"
"${QUIET:-_print_center}" "normal" " Code that was grabbed: $authorization_code " "-"
printf "Output of http server:\n"
cat "$TMPFILE.code"
(rm -f "$TMPFILE.code"&)
return 1
fi
(rm -f "$TMPFILE.code"&)
response_check_refresh_token="$(_curl --compressed "$CURL_PROGRESS" -X POST \
--data "code=$authorization_code&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&redirect_uri=$REDIRECT_URI%3A$server_port_check_refresh_token&grant_type=authorization_code&code_verifier=$code_challenge_check_refresh_token" "$TOKEN_URL")"||:
_clear_line 1 1>&2
refresh_token_value_check_refresh_token="$(printf "%s\n" "$response_check_refresh_token"|_json_value refresh_token 1 1)"||{ printf "%s\n" "Error: Code was not fetched properly , here is some info that maybe helpful.."&&printf "%s\n" "$response_check_refresh_token"&&return 1;}
_set_value direct REFRESH_TOKEN "$refresh_token_value_check_refresh_token"
{ _check_access_token "$account_name_check_refresh_token" skip_check "$response_check_refresh_token"&&_update_config "$refresh_token_name_check_refresh_token" "$refresh_token_value_check_refresh_token" "$CONFIG";}||return 1
}
printf "\n"
}
_set_value direct "$refresh_token_name_check_refresh_token" "$refresh_token_value_check_refresh_token"
_set_value direct REFRESH_TOKEN "$refresh_token_value_check_refresh_token"
return 0
}
_check_access_token(){
export CLIENT_ID CLIENT_SECRET REFRESH_TOKEN CONFIG QUIET
[ -z "${CLIENT_ID:+${CLIENT_SECRET:+$REFRESH_TOKEN}}" ]&&return 1
account_name_check_access_token="${1-}" no_check_check_access_token="${2:-false}" response_json_check_access_token="${3-}"
unset token_name_check_access_token token_expiry_name_check_access_token token_value_check_access_token token_expiry_value_check_access_token response_check_access_token
access_token_regex='ya29\.[0-9A-Za-z_-]+'
token_name_check_access_token="${account_name_check_access_token:+ACCOUNT_${account_name_check_access_token}_}ACCESS_TOKEN"
token_expiry_name_check_access_token="${token_name_check_access_token}_EXPIRY"
_set_value indirect token_value_check_access_token "$token_name_check_access_token"
_set_value indirect token_expiry_value_check_access_token "$token_expiry_name_check_access_token"
[ "$no_check_check_access_token" = skip_check ]||[ -z "$token_value_check_access_token" ]||[ "${token_expiry_value_check_access_token:-0}" -lt "$(_epoch)" ]||! _assert_regex "$access_token_regex" "$token_value_check_access_token"&&{
response_check_access_token="${response_json_check_access_token:-$(curl --compressed -s -X POST --data \
"client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&refresh_token=$REFRESH_TOKEN&grant_type=refresh_token" "$TOKEN_URL")}"||:
if token_value_check_access_token="$(printf "%s\n" "$response_check_access_token"|_json_value access_token 1 1)";then
token_expiry_value_check_access_token="$(($(_epoch)+$(printf "%s\n" "$response_check_access_token"|_json_value expires_in 1 1)-1))"
_update_config "$token_name_check_access_token" "$token_value_check_access_token" "$CONFIG"||return 1
_update_config "$token_expiry_name_check_access_token" "$token_expiry_value_check_access_token" "$CONFIG"||return 1
else
"${QUIET:-_print_center}" "justify" "Error: Something went wrong" ", printing error." "=" 1>&2
printf "%s\n" "$response_check_access_token" 1>&2
printf "%s\n" "If refresh token has expired, then use --oauth-refetch-refresh-token to refetch refresh token, if the error is not clear make a issue on github repository."
return 1
fi
}
_set_value direct ACCESS_TOKEN "$token_value_check_access_token"
_set_value direct ACCESS_TOKEN_EXPIRY "$token_expiry_value_check_access_token"
_set_value direct INITIAL_ACCESS_TOKEN "$ACCESS_TOKEN"
return 0
}
_reload_config(){
export CONFIG
{ [ -r "$CONFIG" ]&&_parse_config "$CONFIG";}||{ printf "" >>"$CONFIG"||return 1;}
return 0
}
_token_bg_service(){
export MAIN_PID ACCESS_TOKEN ACCESS_TOKEN_EXPIRY TMPFILE
[ -z "$MAIN_PID" ]&&return 0
printf "%b\n" "ACCESS_TOKEN=\"$ACCESS_TOKEN\"\nACCESS_TOKEN_EXPIRY=\"$ACCESS_TOKEN_EXPIRY\"" >|"${TMPFILE}_ACCESS_TOKEN"
{
until ! kill -0 "$MAIN_PID" 2>|/dev/null 1>&2;do
. "${TMPFILE}_ACCESS_TOKEN"
CURRENT_TIME="$(_epoch)"
REMAINING_TOKEN_TIME="$((ACCESS_TOKEN_EXPIRY-CURRENT_TIME))"
if [ "$REMAINING_TOKEN_TIME" -le 300 ];then
CONFIG="${TMPFILE}_ACCESS_TOKEN" _timeout 30 _check_access_token "" skip_check||:
else
TOKEN_PROCESS_TIME_TO_SLEEP="$(if [ "$REMAINING_TOKEN_TIME" -le 301 ];then
printf "0\n"
else
printf "%s\n" "$((REMAINING_TOKEN_TIME-300))"
fi)"
sleep "$TOKEN_PROCESS_TIME_TO_SLEEP"
fi
sleep 1
done
}&
export ACCESS_TOKEN_SERVICE_PID="$!"
return 0
}
_actual_size_in_bytes(){
file_actual_size_in_bytes="${1:?Error: give filename}"
{ _tmp="$(BLOCK_SIZE=512 BLOCKSIZE=512 du -- "$file_actual_size_in_bytes")"&&_tmp="${_tmp%%"$(printf '\t')"*}"&&printf "%s\n" "$((_tmp*512))";}||return 1
}
_bytes_to_human(){
b_bytes_to_human="$(printf "%.0f\n" "${1:-0}")" s_bytes_to_human=0
d_bytes_to_human='' type_bytes_to_human=''
while [ "$b_bytes_to_human" -gt 1024 ];do
d_bytes_to_human="$(printf ".%02d" $((b_bytes_to_human%1024*100/1024)))"
b_bytes_to_human=$((b_bytes_to_human/1024))&&s_bytes_to_human=$((s_bytes_to_human+=1))
done
j=0&&for i in B KB MB GB TB PB EB YB ZB;do
j="$((j+=1))"&&[ "$((j-1))" = "$s_bytes_to_human" ]&&type_bytes_to_human="$i"&&break
continue
done
printf "%s\n" "$b_bytes_to_human$d_bytes_to_human $type_bytes_to_human"
}
_check_debug(){
export DEBUG QUIET
if [ -n "$DEBUG" ];then
set -x&&PS4='-> '
_print_center(){
if [ $# = 3 ];then
printf "%s\n" "$2"
else
printf "%s%s\n" "$2" "$3"
fi
}
_clear_line(){ :;}
_move_cursor(){ :;}
_newline(){ :;}
else
if [ -z "$QUIET" ];then
if _support_ansi_escapes;then
if ! _required_column_size;then
_print_center(){ { [ $# = 3 ]&&printf "%s\n" "[ $2 ]";}||{ printf "%s\n" "[ $2$3 ]";};}
fi
export EXTRA_LOG="_print_center" CURL_PROGRESS="-#" SUPPORT_ANSI_ESCAPES="true"
else
_print_center(){ { [ $# = 3 ]&&printf "%s\n" "[ $2 ]";}||{ printf "%s\n" "[ $2$3 ]";};}
_clear_line(){ :;}&&_move_cursor(){ :;}
fi
_newline(){ printf "%b" "$1";}
else
_print_center(){ :;}&&_clear_line(){ :;}&&_move_cursor(){ :;}&&_newline(){ :;}
fi
set +x
fi
{
[ "${_SHELL-}" = "bash" ]&&tmp="-f"&&export "${tmp?}" _newline \
_print_center \
_clear_line
} 2>|/dev/null 1>&2||:
}
_check_internet(){
"${EXTRA_LOG-}" "justify" "Checking Internet Connection.." "-"
if ! _timeout 10 _curl -Is https://google.com --compressed;then
_clear_line 1
"${QUIET:-_print_center}" "justify" "Error: Internet connection" " not available." "="
return 1
fi
_clear_line 1
}
_clear_line(){
printf "\033[%sA\033[2K" "$1"
}
_curl(){
curl ${CURL_FLAGS-} "$@"||return 1
}
_display_time(){
t_display_time="$1" day_display_time="$((t_display_time/60/60/24))"
hr_display_time="$((t_display_time/60/60%24))" min_display_time="$((t_display_time/60%60))" sec_display_time="$((t_display_time%60))"
[ "$day_display_time" -gt 0 ]&&printf '%d days ' "$day_display_time"
[ "$hr_display_time" -gt 0 ]&&printf '%d hrs ' "$hr_display_time"
[ "$min_display_time" -gt 0 ]&&printf '%d minute(s) ' "$min_display_time"
[ "$day_display_time" -gt 0 ]||[ "$hr_display_time" -gt 0 ]||[ "$min_display_time" -gt 0 ]&&printf 'and '
printf '%d seconds\n' "$sec_display_time"
}
_get_latest_sha(){
export TYPE TYPE_VALUE REPO
unset latest_sha_get_latest_sha raw_get_latest_sha
case "${1:-$TYPE}" in
branch)\
latest_sha_get_latest_sha="$(\
raw_get_latest_sha="$(curl --compressed -s https://github.com/"${3:-$REPO}"/commits/"${2:-$TYPE_VALUE}".atom -r 0-2000)"
_tmp="$(printf "%s\n" "$raw_get_latest_sha"|grep -o 'Commit\/.*<' -m1||:)"&&_tmp="${_tmp##*\/}"&&printf "%s\n" "${_tmp%%<*}")"
;;
release)\
latest_sha_get_latest_sha="$(\
raw_get_latest_sha="$(curl -L --compressed -s https://github.com/"${3:-$REPO}"/releases/"${2:-$TYPE_VALUE}")"
_tmp="$(printf "%s\n" "$raw_get_latest_sha"|grep '="/'"${3:-$REPO}""/commit" -m1||:)"&&_tmp="${_tmp##*commit\/}"&&printf "%s\n" "${_tmp%%\"*}")"
;;
*):
esac
printf "%b" "${latest_sha_get_latest_sha:+$latest_sha_get_latest_sha\n}"
}
_is_fd_open(){
for fd in ${1:?};do
if ! { true >&"$fd";} 2<>/dev/null;then
printf "%s\n" "Error: fd $fd not open."
return 1
fi
done
}
_json_value(){
{ [ "$2" -gt 0 ] 2>|/dev/null&&no_of_lines_json_value="$2";}||:
{ [ "$3" -gt 0 ] 2>|/dev/null&&num_json_value="$3";}||{ ! [ "$3" = all ]&&num_json_value=1;}
_tmp="$(grep -o "\"$1\":.*" ${no_of_lines_json_value:+-m} $no_of_lines_json_value)"||return 1
printf "%s\n" "$_tmp"|sed -e 's|.*"'"$1""\":||" -e 's/[",]*$//' -e 's/["]*$//' -e 's/[,]*$//' -e "s/^ //" -e 's/^"//' -n -e "$num_json_value"p||:
return 0
}
_move_cursor(){
printf "\033[%sA" "${1:?Error: Num of line}"
}
_parse_config(){
_config_file_parse_config="${1:?Error: Profile config file}"
print_parse_config="${2:-false}"
[ -r "$_config_file_parse_config" ]||{
printf "%s\n" "Error: Given config file ( $_config_file_parse_config ) is not readable."
return 1
}
while IFS='=' read -r key val;do
{ [ -n "$key" ]&&[ -n "$val" ]&&[ -n "${key##\#*}" ];}||continue
key="${key#"${key%%[![:space:]]*}"}"
val="${val#"${val%%[![:space:]]*}"}"
key="${key%"${key##*[![:space:]]}"}"
val="${val%"${val##*[![:space:]]}"}"
case "$val" in
\"*\")val="${val#\"}" val="${val%\"}";;
\'*\')val="${val#\'}" val="${val%\'}";;
*):
esac
export "$key=$val" 2>/dev/null||printf "%s\n" "Warning: $key is not a valid variable name."
[ "$print_parse_config" = true ]&&echo "$key=$val"
done <"$_config_file_parse_config"
return 0
}
_print_center(){
[ $# -lt 3 ]&&printf "Missing arguments\n"&&return 1
term_cols_print_center="${COLUMNS-}"
type_print_center="$1" filler_print_center=""
case "$type_print_center" in
normal)out_print_center="$2"&&symbol_print_center="$3";;
justify)if
[ $# = 3 ]
then
input1_print_center="$2" symbol_print_center="$3" to_print_print_center="" out_print_center=""
to_print_print_center="$((term_cols_print_center-5))"
{ [ "${#input1_print_center}" -gt "$to_print_print_center" ]&&out_print_center="[ $(printf "%.${to_print_print_center}s\n" "$input1_print_center")..]";}||{ out_print_center="[ $input1_print_center ]";}
else
input1_print_center="$2" input2_print_center="$3" symbol_print_center="$4" to_print_print_center="" temp_print_center="" out_print_center=""
to_print_print_center="$((term_cols_print_center*47/100))"
{ [ "${#input1_print_center}" -gt "$to_print_print_center" ]&&temp_print_center=" $(printf "%.${to_print_print_center}s\n" "$input1_print_center")..";}||{ temp_print_center=" $input1_print_center";}
to_print_print_center="$((term_cols_print_center*46/100))"
{ [ "${#input2_print_center}" -gt "$to_print_print_center" ]&&temp_print_center="$temp_print_center$(printf "%.${to_print_print_center}s\n" "$input2_print_center").. ";}||{ temp_print_center="$temp_print_center$input2_print_center ";}
out_print_center="[$temp_print_center]"
fi
;;
*)return 1
esac
str_len_print_center="${#out_print_center}"
[ "$str_len_print_center" -ge "$((term_cols_print_center-1))" ]&&{
printf "%s\n" "$out_print_center"&&return 0
}
filler_print_center_len="$(((term_cols_print_center-str_len_print_center)/2))"
i_print_center=1&&while [ "$i_print_center" -le "$filler_print_center_len" ];do
filler_print_center="$filler_print_center$symbol_print_center"&&i_print_center="$((i_print_center+1))"
done
printf "%s%s%s" "$filler_print_center" "$out_print_center" "$filler_print_center"
[ "$(((term_cols_print_center-str_len_print_center)%2))" -ne 0 ]&&printf "%s" "$symbol_print_center"
printf "\n"
return 0
}
_print_center_quiet(){
{ [ $# = 3 ]&&printf "%s\n" "$2";}||{ printf "%s%s\n" "$2" "$3";}
}
_support_ansi_escapes(){
unset ansi_escapes
case "${TERM-}" in
xterm*|rxvt*|urxvt*|linux*|vt*|screen*)ansi_escapes="true";;
*):
esac
{ [ -t 2 ]&&[ -n "$ansi_escapes" ]&&return 0;}||return 1
}
_timeout(){
timeout_timeout="${1:?Error: Specify Timeout}"&&shift
{
"$@"&
child="$!"
trap -- "" TERM
{
sleep "$timeout_timeout"
kill -9 "$child"
}&
wait "$child"
} 2>|/dev/null 1>&2
}
_update_config(){
[ $# -lt 3 ]&&printf "Missing arguments\n"&&return 1
value_name_update_config="$1" value_update_config="$2" config_path_update_config="$3"
! [ -f "$config_path_update_config" ]&&: >|"$config_path_update_config"
chmod u+w -- "$config_path_update_config"||return 1
printf "%s\n%s\n" "$(grep -v -e "^$" -e "^$value_name_update_config=" -- "$config_path_update_config"||:)" \
"$value_name_update_config=\"$value_update_config\"" >|"$config_path_update_config"||return 1
chmod a-w-r-x,u+r -- "$config_path_update_config"||return 1
return 0
}
_api_request(){
_curl --compressed ${CURL_PROGRESS-} \
-e "https://drive.google.com" \
"${API_URL:?}/drive/${API_VERSION:?}/${1:?}&key=${API_KEY:?}&supportsAllDrives=true&includeItemsFromAllDrives=true"||return 1
_clear_line 1 1>&2
}
_api_request_oauth(){
. "${TMPFILE:?}_ACCESS_TOKEN"
_curl --compressed ${CURL_PROGRESS-} \
-H "Authorization: Bearer ${ACCESS_TOKEN:?}" \
"${API_URL:?}/drive/${API_VERSION:?}/${1:?}&supportsAllDrives=true&includeItemsFromAllDrives=true"||return 1
_clear_line 1 1>&2
}
_check_id(){
export EXTRA_LOG API_REQUEST_FUNCTION QUIET
id_check_id="${1:?_check_id}" json_check_id=""
__error_check_id(){
_clear_line 1
"${QUIET:-_print_center}" "justify" "${1:?__error_check_id}" "="
[ -n "$2" ]&&{
if [ -n "$3" ];then
"${QUIET:-_print_center}" "normal" "$2" " "
else
printf "%s\n" "$2"
fi
}
_newline "\n"
}
"$EXTRA_LOG" "justify" "Validating URL/ID.." "-"
json_check_id="$("$API_REQUEST_FUNCTION" "files/$id_check_id?alt=json&fields=name,size,mimeType")"||{
__error_check_id "Error: Cannot validate URL/ID" "$json_check_id"
return 1
}
printf "%s\n" "$json_check_id"|_json_value code 1 1 2>|/dev/null 1>&2&&__error_check_id "Invalid URL/ID" "$id_check_id" pretty&&return 1
NAME="$(printf "%s\n" "$json_check_id"|_json_value name 1 1)"||{
__error_check_id "Cannot fetch name."
return 1
}
mime_check_id="$(printf "%s\n" "$json_check_id"|_json_value mimeType 1 1)"||{
__error_check_id "Cannot fetch mimetype."
return 1
}
_clear_line 1
case "$mime_check_id" in
"application/vnd.google-apps.folder")\
FOLDER_ID="$id_check_id"
_print_center "justify" "Folder Detected" "="
;;
"application/vnd.google-apps.document")\
FILE_ID="$id_check_id" \
FILE_MIME_TYPE="$mime_check_id"
_print_center "justify" "Document Detected" "="
;;
*)\
SIZE="$(printf "%s\n" "$json_check_id"|_json_value size 1 1)"||{
printf "\n"&&__error_check_id "Cannot fetch size of file."&&return 1
}
FILE_ID="$id_check_id" FILE_MIME_TYPE="$mime_check_id"
_print_center "justify" "File Detected" "="
esac
_newline "\n"
export NAME SIZE FILE_ID FILE_MIME_TYPE FOLDER_ID
return 0
}
_extract_id(){
[ $# = 0 ]&&printf "Missing arguments\n"&&return 1
id_extract_id="$1"
case "$id_extract_id" in
*'drive.google.com'*'id='*)_tmp="${id_extract_id##*id=}"&&_tmp="${_tmp%%\?*}"&&id_extract_id="${_tmp%%\&*}";;
*'drive.google.com'*'file/d/'*|'http'*'docs.google.com'*'/d/'*)_tmp="${id_extract_id##*\/d\/}"&&_tmp="${_tmp%%\/*}"&&_tmp="${_tmp%%\?*}"&&id_extract_id="${_tmp%%\&*}";;
*'drive.google.com'*'drive'*'folders'*)_tmp="${id_extract_id##*\/folders\/}"&&_tmp="${_tmp%%\?*}"&&id_extract_id="${_tmp%%\&*}";;
*):
esac
if [ -n "$2" ];then
_set_value d "$2" "$id_extract_id"
else
printf "%b" "${id_extract_id:+$id_extract_id\n}"
fi
}
_get_export_mime(){
[ $# = 0 ]&&printf "Missing arguments\n"&&return 1
type_get_export_mime="$1"
given_format_get_export_mime="$2"
ext_get_export_mime=""
format_get_export_mime=""
case "$given_format_get_export_mime" in
docx|application/vnd.google-apps.document|application/vnd.openxmlformats-officedocument.wordprocessingml.document)format_get_export_mime="application%2Fvnd.openxmlformats-officedocument.wordprocessingml.document" ext_get_export_mime="docx";;
odt|application/vnd.oasis.opendocument.text)format_get_export_mime="application%2Fvnd.oasis.opendocument.text" ext_get_export_mime="odt";;
rtf|application/rtf)format_get_export_mime="application%2Frtf" ext_get_export_mime="rtf";;
pdf|application/pdf)format_get_export_mime="application%2Fpdf" ext_get_export_mime="pdf";;
txt|text/plain)format_get_export_mime="text%2Fplain" ext_get_export_mime="plain";;
zip|application/zip)format_get_export_mime="application%2Fzip" ext_get_export_mime="zip";;
epub|"application/epub+zip")format_get_export_mime="application%2Fepub%2Bzip" ext_get_export_mime="epub";;
xlsx|application/vnd.google-apps.spreadsheet|application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)format_get_export_mime="application%2Fvnd.openxmlformats-officedocument.spreadsheetml.sheet" ext_get_export_mime="xlsx";;
ods|application/x-vnd.oasis.opendocument.spreadsheet)format_get_export_mime="application%2Fx-vnd.oasis.opendocument.spreadsheet" ext_get_export_mime="ods";;
csv|text/csv)format_get_export_mime="text%2Fcsv" ext_get_export_mime="csv";;
tsv|text/tab-separated-values)format_get_export_mime="text%2Ftab-separated-values" ext_get_export_mime="tsv";;
pptx|application/vnd.openxmlformats-officedocument.presentationml.presentation)format_get_export_mime="application%2Fvnd.openxmlformats-officedocument.presentationml.presentation" ext_get_export_mime="pptx";;
odp|application/vnd.oasis.opendocument.presentation)format_get_export_mime="application%2Fvnd.oasis.opendocument.presentation" ext_get_export_mime="odp";;
jpg|image/jpeg)format_get_export_mime="image%2Fjpeg" ext_get_export_mime="jpg";;
png|image/png)format_get_export_mime="image%2Fpng" ext_get_export_mime="png";;
svg|image/svg+xml)format_get_export_mime="image%2Fsvg%2Bxml" ext_get_export_mime="svg";;
json|application/vnd.google-apps.script+json)format_get_export_mime="application%2Fvnd.google-apps.script%2Bjson" ext_get_export_mime="json";;
*)format_get_export_mime="" ext_get_export_mime=""
esac
if [ "$type_get_export_mime" = "ext" ];then
printf "%s" "$ext_get_export_mime"
elif [ "$type_get_export_mime" = "mime" ];then
printf "%s" "$format_get_export_mime"
fi
}
_cookies_and_document_stuff(){
"$EXTRA_LOG" "justify" "Fetching" " ${1:?}.." "-"
_curl --compressed $CURL_PROGRESS ${3-} \
"${4:---header}" "${5-}" \
-c "${TMPFILE}_${file_id_download_file}_COOKIE" -o "${TMPFILE}_${file_id_download_file}_misc" \
"${2:?}"||return 1
print '' >>"${TMPFILE}_${file_id_download_file}_misc"
for _ in 1 2;do _clear_line 1;done
}
_common_stuff(){
export OAUTH_ENABLED TMPFILE ACCESS_TOKEN API_URL API_VERSION API_KEY API_KEY_DOWNLOAD EXTRA_LOG CURL_PROGRESS DOWNLOADER DOCUMENT_FORMAT DOCUMENT_FORMAT_ESCAPED
if [ -n "${OAUTH_ENABLED:-$API_KEY_DOWNLOAD}" ];then
url_download_file="$API_URL/drive/$API_VERSION/files/$file_id_download_file$(case "$mime_download_file" in
"application/vnd.google-apps."*)printf "%s" "/export?mimeType=$DOCUMENT_FORMAT_ESCAPED";;
*)printf "?alt=media"
esac)&supportsAllDrives=true&includeItemsFromAllDrives=true"
if [ -n "$OAUTH_ENABLED" ];then
. "${TMPFILE}_ACCESS_TOKEN"
flag_download_file="--header" flag_value_download_file="Authorization: Bearer $ACCESS_TOKEN"
elif [ -n "$API_KEY_DOWNLOAD" ];then
flag_download_file="--referer" flag_value_download_file="https://drive.google.com"
url_download_file="$url_download_file&key=$API_KEY"
fi
case "$mime_download_file" in
"application/vnd.google-apps."*)_cookies_and_document_stuff "document size" "$url_download_file" "-LI" "$flag_download_file" "$flag_value_download_file"||return 1
server_size_download_file="$(($(_tmp="$(grep -F 'content-length' "${TMPFILE}_${file_id_download_file}_misc")"&&_tmp="${_tmp##content-length: }"&&printf "%s\n" "${_tmp%"$(printf '\r')"}")))"
server_size_readable_download_file="$(_bytes_to_human "$server_size_download_file" 2>|/dev/null)"
_clear_line 1
_print_center "justify" "$name_download_file" " | $server_size_readable_download_file" "="
;;
*):
esac
else
flag_download_file="-b" flag_value_download_file="${TMPFILE}_${file_id_download_file}_COOKIE"
case "$mime_download_file" in
"application/vnd.google-apps."*)\
json_common_stuff="$("$API_REQUEST_FUNCTION" "files/$file_id_download_file?alt=json&fields=exportLinks")"||return 1
url_download_file="$(printf "%s\n" "$json_common_stuff"|_json_value "$DOCUMENT_FORMAT_ESCAPED" 1 1)"||return 0
_cookies_and_document_stuff "cookies and document size" "$url_download_file" "-LI"||return 1
server_size_download_file="$(($(_tmp="$(grep -F 'content-length' "${TMPFILE}_${file_id_download_file}_misc")"&&_tmp="${_tmp##content-length: }"&&printf "%s\n" "${_tmp%"$(printf '\r')"}")))"
server_size_readable_download_file="$(_bytes_to_human "$server_size_download_file" 2>|/dev/null)"
_clear_line 1
_print_center "justify" "$name_download_file" " | $server_size_readable_download_file" "="
;;
*)\
url_download_file="https://drive.google.com/uc?export=download&id=$file_id_download_file"
_cookies_and_document_stuff "cookies" "$url_download_file" "-L"||return 1
confirm_string="$(_tmp="$(grep -F 'download_warning' "${TMPFILE}_${file_id_download_file}_COOKIE")"&&printf "%s\n" "${_tmp##*"$(printf '\t')"}")"||:
[ -z "$confirm_string" ]&&{
confirm_string="$(_tmp="$(grep -Eo "export=download.*$file_id_download_file.*confirm=\w+" "${TMPFILE}_${file_id_download_file}_misc")"&&printf "%s\n" "${_tmp##*=}")"
}
url_download_file="$url_download_file${confirm_string:+&confirm=$confirm_string}"
esac
[ "$DOWNLOADER" = "aria2c" ]&&{
cookies_download_file="$(sed -e "s/^\# .*//g" -e "s/^\#HttpOnly_//g" "${TMPFILE}_${file_id_download_file}_COOKIE")"
printf "%s\n" "$cookies_download_file" >|"${TMPFILE}_${file_id_download_file}_COOKIE"
flag_download_file="--load-cookies"
}
fi
return 0
}
_download_with_aria2c(){
export ARIA_FLAGS QUIET
[ $# -lt 3 ]&&printf "Missing arguments\n"&&return 1
file_id_download_file="$1" name_download_file="$2" mime_download_file="$3" server_size_download_file="$4" parallel_download_file="$5"
unset flag_download_file flag_value_download_file url_download_file cookies_download_file
server_size_readable_download_file="$(_bytes_to_human "$server_size_download_file" 2>|/dev/null)"
_print_center "justify" "$name_download_file" " | $server_size_readable_download_file" "="
_common_stuff||return 1
download_status=0
aria2c $ARIA_FLAGS \
"$flag_download_file" "$flag_value_download_file" \
"$url_download_file" -o "$name_download_file"||download_status=1
if [ "$download_status" -eq 0 ];then
"${QUIET:-_print_center}" "justify" "Downloaded" "="&&_newline "\n"
rm -f -- "$name.aria2"
else
"${QUIET:-_print_center}" "justify" "Error: Incomplete" " download." "=" 1>&2
return 1
fi
_log_in_file "$name_download_file" "$server_size_readable_download_file" "$file_id_download_file"
return 0
}
_download_with_curl(){
export QUIET
[ $# -lt 3 ]&&printf "Missing arguments\n"&&return 1
file_id_download_file="$1" name_download_file="$2" mime_download_file="$3" server_size_download_file="$4" parallel_download_file="$5"
unset range_download_file downloaded_download_file old_downloaded_download_file left_download_file speed_download_file eta_download_file \
flag_download_file flag_value_download_file url_download_file cookies_download_file
server_size_readable_download_file="$(_bytes_to_human "$server_size_download_file" 2>|/dev/null)"
_print_center "justify" "$name_download_file" " | $server_size_readable_download_file" "="
__check_for_resume_download_with_curl(){
if [ -s "$name_download_file" ];then
local_size_download_file="$(_actual_size_in_bytes "$name_download_file")"
if [ "$local_size_download_file" -ge "$((server_size_download_file))" ];then
"${QUIET:-_print_center}" "justify" "File already present" "="&&_newline "\n"
_log_in_file
return 1
else
_print_center "justify" "File is partially" " present, resuming.." "-"
range_download_file="Range: bytes=$local_size_download_file-$server_size_download_file"
fi
else
[ "$((server_size_download_file))" -gt 0 ]&&range_download_file="Range: bytes=0-$server_size_download_file"
_print_center "justify" "Downloading file.." "-"
fi
}
case "$mime_download_file" in
"application/vnd.google-apps.document")_common_stuff||return 1
__check_for_resume_download_with_curl||return 0
;;
*)__check_for_resume_download_with_curl||return 0
_common_stuff||return 1
esac
_curl -Ls \
--header "$range_download_file" \
"$flag_download_file" "$flag_value_download_file" \
"$url_download_file" >>"$name_download_file"&
pid="$!"
if [ -n "$parallel_download_file" ];then
wait "$pid" 2>|/dev/null 1>&2
else
until [ -f "$name_download_file" ]||! kill -0 "$pid" 2>|/dev/null 1>&2;do sleep 0.5;done
_newline "\n\n"
until ! kill -0 "$pid" 2>|/dev/null 1>&2;do
downloaded_download_file="$(_actual_size_in_bytes "$name_download_file")"
left_download_file="$((server_size_download_file-downloaded_download_file))"
speed_download_file="$((downloaded_download_file-old_downloaded_download_file))"
{ [ "$speed_download_file" -gt 0 ]&&eta_download_file="$(_display_time "$((left_download_file/speed_download_file))")";}||eta_download_file=""
sleep 0.5
_move_cursor 2
_print_center "justify" "Downloaded: $(_bytes_to_human "$downloaded_download_file") " "| Left: $(_bytes_to_human "$left_download_file")" "="
_print_center "justify" "Speed: $(_bytes_to_human "$speed_download_file")/s " "| ETA: ${eta_download_file:-Unknown}" "-"
old_downloaded_download_file="$downloaded_download_file"
done
fi
if [ "$(_actual_size_in_bytes "$name_download_file")" -ge "$((server_size_download_file))" ];then
for _ in 1 2 3;do _clear_line 1;done
"${QUIET:-_print_center}" "justify" "Downloaded" "="&&_newline "\n"
rm -f -- "$name.aria2"
else
"${QUIET:-_print_center}" "justify" "Error: Incomplete" " download." "=" 1>&2
return 1
fi
_log_in_file "$name_download_file" "$server_size_readable_download_file" "$file_id_download_file"
return 0
}
_download_file_main(){
export DOWNLOADER DOCUMENT_FORMAT
[ $# -lt 2 ]&&printf "Missing arguments\n"&&return 1
unset line_download_file_main fileid_download_file_main name_download_file_main mime_download_file_main size_download_file_main parallel_download_file_main RETURN_STATUS sleep_download_file_main&&retry_download_file_main="${RETRY:-0}"
if [ "$1" = parse ];then
line_download_file_main="${2:?}"
parallel_download_file_main="$3"
root_download_file_main="${line_download_file_main%%"|:_//_:|"*}"
fileid_download_file_main="${line_download_file_main##"$root_download_file_main""|:_//_:|"}"
fileid_download_file_main="${fileid_download_file_main%%"|:_//_:|"*}"
name_download_file_main="${line_download_file_main##*"$fileid_download_file_main""|:_//_:|"}"
name_download_file_main="${name_download_file_main%%"|:_//_:|"*}"
size_download_file_main="${line_download_file_main##*"$name_download_file_main""|:_//_:|"}"
size_download_file_main="${size_download_file_main%%"|:_//_:|"*}"
mime_download_file_main="${line_download_file_main##*"|:_//_:|"}"
else
fileid_download_file_main="${2:?}"
name_download_file_main="${3:?}"
mime_download_file_main="$4"
size_download_file_main="$5"
size_download_file_main="$((size_download_file_main))"
fi
[ -z "${fileid_download_file_main:+$name_download_file_main}" ]&&return 0
case "$mime_download_file_main" in
"application/vnd.google-apps."*)if
[ -z "${DOCUMENT_FORMAT:+$DOCUMENT_FORMAT_ESCAPED}" ]
then
DOCUMENT_FORMAT="$(_get_export_mime ext "$mime_download_file_main")"
DOCUMENT_FORMAT_ESCAPED="$(_get_export_mime mime "$mime_download_file_main")"
fi
name_download_file_main="$name_download_file_main.$DOCUMENT_FORMAT"
;;
*):
esac
unset RETURN_STATUS&&until [ "$retry_download_file_main" -le 0 ]&&[ -n "$RETURN_STATUS" ];do
if [ -n "$parallel_download_file_main" ];then
([ "$1" = parse ]&&{
cd -- "$root_download_file_main"||return 1
}
"_download_with_$DOWNLOADER" "$fileid_download_file_main" "$name_download_file_main" "$mime_download_file_main" "$size_download_file_main" true 2>|/dev/null 1>&2)&&\
RETURN_STATUS=1&&break
else
([ "$1" = parse ]&&{
cd -- "$root_download_file_main"||return 1
}
"_download_with_$DOWNLOADER" "$fileid_download_file_main" "$name_download_file_main" "$mime_download_file_main" "$size_download_file_main")&&\
RETURN_STATUS=1&&break
fi
sleep "$((sleep_download_file_main+=1))"
RETURN_STATUS=2 retry_download_file_main="$((retry_download_file_main-1))"&&continue
done
{ [ "$RETURN_STATUS" = 1 ]&&printf "%b" "${parallel_download_file_main:+$RETURN_STATUS\n}";}||printf "%b" "${parallel_download_file_main:+$RETURN_STATUS\n}" 1>&2
return 0
}
_fetch_folderinfo(){
export EXTRA_LOG QUIET API_REQUEST_FUNCTION INCLUDE_FILES EXCLUDE_FILES VERBOSE SKIP_SUBDIRS
parse_fetch_folderinfo="${1:?}"
unset json_search_fetch_folderinfo json_search_fragment_fetch_folderinfo next_page_token_fetch_folderinfo \
error_status_fetch_folderinfo success_status_fetch_folderinfo \
files_id_fetch_folderinfo folders_id_fetch_folderinfo files_size_fetch_folderinfo \
files_name_fetch_folderinfo folders_name_fetch_folderinfo files_mime_fetch_folderinfo \
num_of_files_fetch_folderinfo num_of_folders_fetch_folderinfo
if [ "$parse_fetch_folderinfo" = "true" ];then
mode_fetch_folderinfo="${2:?_fetch_folderinfo: 2}"
line_fetch_folderinfo="${3:?_fetch_folderinfo: 3}"
files_list_fetch_folderinfo="${4:?_fetch_folderinfo: 4}" folders_list_fetch_folderinfo="${5:?_fetch_folderinfo: 5}"
name_fetch_folderinfo="${line_fetch_folderinfo##*"|:_//_:|"}"
_tmp_root_fetch_folderinfo="${line_fetch_folderinfo%"|:_//_:|"*}"
_tmp_root_fetch_folderinfo="${_tmp_root_fetch_folderinfo%"|:_//_:|"*}"
root_name_fetch_folderinfo="${_tmp_root_fetch_folderinfo#*"|:_//_:|"}"
_tmp_id_fetch_folderinfo="${line_fetch_folderinfo%%"|:_//_:|""$name_fetch_folderinfo"}"
folder_id_fetch_folderinfo="${_tmp_id_fetch_folderinfo##*"|:_//_:|"}"
else
mode_fetch_folderinfo="${2:?_fetch_folderinfo: 2}"
folder_id_fetch_folderinfo="${3:?_fetch_folderinfo: 3}"
name_fetch_folderinfo="${4:?_fetch_folderinfo: 4}" root_name_fetch_folderinfo="${5:?_fetch_folderinfo: 5}"
files_list_fetch_folderinfo="${6:?_fetch_folderinfo: 6}" folders_list_fetch_folderinfo="${7:?_fetch_folderinfo: 7}"
fi
if [ "$root_name_fetch_folderinfo" = "$PWD" ];then
_newline "\n"
else
"$EXTRA_LOG" "justify" "Root folder name: ${root_name_fetch_folderinfo##"$PWD"/}" "="
fi
"$EXTRA_LOG" "justify" "$name_fetch_folderinfo" "="
"$EXTRA_LOG" "justify" "Fetching folder" " details.." "-"
_search_error_message_fetch_folderinfo(){
"${QUIET:-_print_center}" "justify" "Error: Cannot" ", fetch folder details." "="
printf "%s\n" "${1-}"&&return 1
}
if json_search_fetch_folderinfo="$("$API_REQUEST_FUNCTION" "files?q=%27$folder_id_fetch_folderinfo%27+in+parents&fields=nextPageToken,files(name,size,id,mimeType)&pageSize=1000&orderBy=name")";then
while :;do
next_page_token_fetch_folderinfo="$(printf "%s\n" "${json_search_fragment_fetch_folderinfo:-$json_search_fetch_folderinfo}"|_json_value nextPageToken 1 1||:)"
[ -z "$next_page_token_fetch_folderinfo" ]&&break
json_search_fragment_fetch_folderinfo="$("$API_REQUEST_FUNCTION" "files?q=%27$folder_id_fetch_folderinfo%27+in+parents&fields=nextPageToken,files(name,size,id,mimeType)&pageSize=1000&orderBy=name&pageToken=$next_page_token_fetch_folderinfo")"||_search_error_message_fetch_folderinfo "$json_search_fragment_fetch_folderinfo"
json_search_fetch_folderinfo="$json_search_fetch_folderinfo
$json_search_fragment_fetch_folderinfo"
done
else
_search_error_message_fetch_folderinfo "$json_search_fetch_folderinfo"
fi&&_clear_line 1
"$EXTRA_LOG" "justify" "Preparing files list.." "="
files_id_fetch_folderinfo="$(printf "%s\n" "$json_search_fetch_folderinfo"|_json_value id all all)"||:
files_size_fetch_folderinfo="$(printf "%s\n" "$json_search_fetch_folderinfo"|_json_value size all all)"||:
files_name_fetch_folderinfo="$(printf "%s\n" "$json_search_fetch_folderinfo"|_json_value name all all)"||:
files_mime_fetch_folderinfo="$(printf "%s\n" "$json_search_fetch_folderinfo"|_json_value mimeType all all)"||:
chmod +w+r -- "$files_list_fetch_folderinfo"
exec 5<<EOF
$(printf "%s\n" "$files_id_fetch_folderinfo")
EOF
exec 6<<EOF
$(printf "%s\n" "$files_size_fetch_folderinfo")
EOF
exec 7<<EOF
$(printf "%s\n" "$files_name_fetch_folderinfo")
EOF
exec 8<<EOF
$(printf "%s\n" "$files_mime_fetch_folderinfo")
EOF
while IFS= read -r id <&5&&read -r size <&6&&read -r name <&7&&read -r mime <&8;do
[ -n "${id:+$name}" ]&&printf "%s\n" "$root_name_fetch_folderinfo/$name_fetch_folderinfo|:_//_:|$id|:_//_:|$name|:_//_:|$((size))|:_//_:|$mime"
done >>"$files_list_fetch_folderinfo"
exec 5<&-&&exec 6<&-&&exec 7<&-&&exec 8<&-
_clear_line 1
chmod -w+r -- "$files_list_fetch_folderinfo"
if [ -f "$name_fetch_folderinfo" ];then
name_fetch_folderinfo="$name_fetch_folderinfo$(_epoch)"
fi
mkdir -p -- "$root_name_fetch_folderinfo/$name_fetch_folderinfo"
"$EXTRA_LOG" "justify" "Preparing sub folders list.." "="
folders_id_fetch_folderinfo="$(printf "%s\n" "$json_search_fetch_folderinfo"|grep '"mimeType":.*folder.*' -B2|_json_value id all all)"||:
folders_name_fetch_folderinfo="$(printf "%s\n" "$json_search_fetch_folderinfo"|grep '"mimeType":.*folder.*' -B1|_json_value name all all)"||:
chmod +w+r -- "$folders_list_fetch_folderinfo"
exec 5<<EOF
$(printf "%s\n" "$folders_id_fetch_folderinfo")
EOF
exec 6<<EOF
$(printf "%s\n" "$folders_name_fetch_folderinfo")
EOF
_tmp_folders_list_fetch_folderinfo="$(while IFS= read -r id <&5&&read -r name <&6;do
[ -n "${id:+$name}" ]&&printf "%s\n" "$folder_id_fetch_folderinfo|:_//_:|$root_name_fetch_folderinfo/$name_fetch_folderinfo|:_//_:|$id|:_//_:|$name"
done)"
printf "%s" "$_tmp_folders_list_fetch_folderinfo" >>"$folders_list_fetch_folderinfo"
exec 5<&-&&exec 6<&-
chmod -w+r -- "$folders_list_fetch_folderinfo"
_clear_line 1
for _ in 1 2;do _clear_line 1;done
[ "$mode_fetch_folderinfo" = "alt" ]||return 0
if [ -z "$SKIP_SUBDIRS" ]&&[ -n "$folders_list_fetch_folderinfo" ];then
while IFS= read -r line <&4&&{ [ -n "$line" ]||continue;};do
_fetch_folderinfo true "$mode_fetch_folderinfo" "$line" "$files_list_fetch_folderinfo" "$folders_list_fetch_folderinfo"
done 4<<EOF
$(printf "%s\n" "$_tmp_folders_list_fetch_folderinfo")
EOF
fi
return 0
}
_download_folder(){
export EXTRA_LOG QUIET API_REQUEST_FUNCTION INCLUDE_FILES EXCLUDE_FILES TMPFILE VERBOSE SKIP_SUBDIRS NO_OF_PARALLEL_JOBS
[ $# = 4 ]&&printf "Missing arguments\n"&&return 1
mode_download_folder="$1" folder_id_download_folder="$2" name_download_folder="$3" root_download_folder="${4:-$PWD}" parallel_download_folder="$5"
unset error_status_download_folder success_status_download_folder num_of_files_download_folder num_of_folders_download_folder
if [ "$mode_download_folder" = "alt" ];then
files_list_download_folder="${TMPFILE}_files_list"
folders_list_download_folder="${TMPFILE}_folders_list"
else
files_list_download_folder="${TMPFILE}_files_list_$folder_id_download_folder"
folders_list_download_folder="${TMPFILE}_folders_list_$folder_id_download_folder"
fi
printf '' >|"$files_list_download_folder"
printf '' >|"$folders_list_download_folder"
_fetch_folderinfo false "$mode_download_folder" "$folder_id_download_folder" "$name_download_folder" "$root_download_folder" \
"$files_list_download_folder" "$folders_list_download_folder" "$parallel_download_folder"
chmod +w+r -- "$files_list_download_folder" "$folders_list_download_folder"
[ -n "$INCLUDE_FILES" ]&&_tmp_filesinfo="$(grep -E "$INCLUDE_FILES" "$files_list_download_folder")"&&printf "%s\n" "$_tmp_filesinfo" >>"$files_list_download_folder"
[ -n "$EXCLUDE_FILES" ]&&_tmp_filesinfo="$(grep -Ev "$EXCLUDE_FILES" "$files_list_download_folder")"&&printf "%s\n" "$_tmp_filesinfo" >>"$files_list_download_folder"
chmod -w+r -- "$files_list_download_folder" "$folders_list_download_folder"
num_of_files_download_folder="$(_count <"$files_list_download_folder")"
num_of_folders_download_folder="$(_count <"$folders_list_download_folder")"
{ [ "$mode_download_folder" = "alt" ]&&_tmp_sum_download_folder="$((num_of_files_download_folder))";}||_tmp_sum_download_folder="$((num_of_files_download_folder+num_of_folders_download_folder))"
[ "$((_tmp_sum_download_folder))" -eq 0 ]&&for _ in 1 2;do _clear_line 1;done&&_print_center "justify" "$name_download_folder" " | Empty Folder" "="&&_newline "\n"&&return 0
_print_center "justify" \
"$name_download_folder" \
"${num_of_files_download_folder:+ | $num_of_files_download_folder files}${num_of_folders_download_folder:+ | $num_of_folders_download_folder sub folders}" "="
_newline "\n\n"
if [ "$((num_of_files_download_folder))" -gt 0 ];then
if [ -n "$parallel_download_folder" ];then
NO_OF_PARALLEL_JOBS_FINAL="$((NO_OF_PARALLEL_JOBS>num_of_files_download_folder?num_of_files_download_folder:NO_OF_PARALLEL_JOBS))"
[ -f "$TMPFILE"SUCCESS ]&&rm "$TMPFILE"SUCCESS
[ -f "$TMPFILE"ERROR ]&&rm "$TMPFILE"ERROR
(xargs -P"$NO_OF_PARALLEL_JOBS_FINAL" -I "{}" -n 1 "${_SHELL:-sh}" -c '
                eval "${SOURCE_UTILS}"
                _download_file_main parse "{}" true
            ' <"$files_list_download_folder" 1>|"$TMPFILE"SUCCESS 2>|"$TMPFILE"ERROR)&
pid="$!"
until [ -f "$TMPFILE"SUCCESS ]||[ -f "$TMPFILE"ERROR ];do sleep 0.5;done
_clear_line 1
until ! kill -0 "$pid" 2>|/dev/null 1>&2;do
success_status_download_folder="$(($(_count <"$TMPFILE"SUCCESS)))"
error_status_download_folder="$(($(_count <"$TMPFILE"ERROR)))"
sleep 1
if [ "$((success_status_download_folder+error_status_download_folder))" != "$TOTAL" ];then
printf '%s\r' "$(_print_center "justify" "Status" ": ${success_status_download_folder:-0} Downloaded | ${error_status_download_folder:-0} Failed" "=")"
fi
TOTAL="$((success_status_download_folder+error_status_download_folder))"
done
_newline "\n"
success_status_download_folder="$(($(_count <"$TMPFILE"SUCCESS)))"
error_status_download_folder="$(($(_count <"$TMPFILE"ERROR)))"
_clear_line 1&&_newline "\n"
else
while IFS= read -r line <&4&&{ [ -n "$line" ]||continue;};do
_download_file_main parse "$line"
: "$((RETURN_STATUS<2?(success_status_download_folder+=1):(error_status_download_folder+=1)))"
if [ -z "$VERBOSE" ];then
for _ in 1 2 3 4;do _clear_line 1;done
fi
_print_center "justify" "Status" ": ${success_status_download_folder:-0} Downloaded | ${error_status_download_folder:-0} Failed" "="
done 4<"$files_list_download_folder"
fi
fi
for _ in 1 2;do _clear_line 1;done
[ "$((success_status_download_folder))" -gt 0 ]&&"${QUIET:-_print_center}" "justify" "Downloaded" ": $((success_status_download_folder))" "="
[ "$((error_status_download_folder))" -gt 0 ]&&"${QUIET:-_print_center}" "justify" "Failed" ": $((error_status_download_folder))" "="
_newline "\n"
[ "$mode_download_folder" = "alt" ]&&return 0
if [ -z "$SKIP_SUBDIRS" ]&&[ "$((num_of_folders_download_folder))" -gt 0 ];then
while IFS= read -r line <&4&&{ [ -n "$line" ]||continue;};do
(\
id="${line%"|:_//_:|"*}"
id="${id##*"|:_//_:|"}"
name="${line##*"|:_//_:|"}"
root="${line#*"|:_//_:|"}"
root="${root%%"|:_//_:|"*}"
_download_folder "$mode_download_folder" "$id" "$name" "$root" "${parallel-}")
done 4<"$folders_list_download_folder"
fi
(rm -f -- "$files_list_download_folder" "$folders_list_download_folder")&
return 0
}
_log_in_file(){
export LOG_FILE_ID
[ -z "$LOG_FILE_ID" ]||[ -d "$LOG_FILE_ID" ]&&return 0
{
printf "%s\n" "Name: $1"
printf "%s\n" "Size: $2"
printf "%s\n\n" "ID: $3"
} >>"$LOG_FILE_ID"
}
_cleanup_config(){
config="${1:?Error: Missing config}"&&unset values_regex _tmp
! [ -f "$config" ]&&return 0
while read -r line <&4&&[ -n "$line" ];do
expiry_value_name="${line%%=*}"
token_value_name="${expiry_value_name%%_EXPIRY}"
_tmp="${line##*=}"&&_tmp="${_tmp%\"}"&&expiry="${_tmp#\"}"
[ "$expiry" -le "$(_epoch)" ]&&values_regex="${values_regex:+$values_regex|}$expiry_value_name=\".*\"|$token_value_name=\".*\""
done 4<<EOF
$(grep -F ACCESS_TOKEN_EXPIRY -- "$config"||:)
EOF
chmod u+w -- "$config"&&printf "%s\n" "$(grep -Ev "^\$${values_regex:+|$values_regex}" -- "$config")" >|"$config"&&chmod "a-w-r-x,u+r" -- "$config"
return 0
}
_setup_arguments(){
[ $# = 0 ]&&printf "Missing arguments\n"&&return 1
unset CURL_FLAGS
export DOWNLOADER="curl"
export CURL_PROGRESS="-s" EXTRA_LOG=":"
export CONFIG="$HOME/.gdl.conf"
export API_URL="https://www.googleapis.com"
export API_VERSION="v3" \
SCOPE="$API_URL/auth/drive" \
REDIRECT_URI="http%3A//localhost" \
TOKEN_URL="https://accounts.google.com/o/oauth2/token"
_parse_arguments "_parser_setup_flags" "$@"||return 1
_check_debug
[ -n "$QUIET" ]&&export CURL_PROGRESS="-s" ARIA_FLAGS=" $ARIA_FLAGS -q "
ARIA_extra_flags="" CURL_extra_flags=""
for downloader in CURL ARIA;do
extra_flags="" flag="" value=""
for var in SPEED_LIMIT USER_AGENT PROXY;do
_set_value i value "$var"
[ -n "$value" ]&&{
_set_value i flag "${downloader}_${var}_FLAG"
extra_flags="$extra_flags $flag $value"
}
done
_set_value d "${downloader}_extra_flags" "$extra_flags"
done
export ARIA_FLAGS="$ARIA_FLAGS --auto-file-renaming=false --continue $ARIA_extra_flags"
export CURL_FLAGS="$CURL_FLAGS $CURL_extra_flags"
[ -n "$OAUTH_ENABLED" ]&&unset API_KEY_DOWNLOAD
[ -n "$API_KEY_DOWNLOAD" ]&&"${UPDATE_DEFAULT_API_KEY:-:}" API_KEY "${API_KEY-}" "$CONFIG"
[ -n "$DELETE_ACCOUNT_NAME" ]&&_delete_account "$DELETE_ACCOUNT_NAME"
[ -n "$LIST_ACCOUNTS" ]&&_all_accounts
[ -z "$INPUT_ID_1" ]&&{
[ -z "${DELETE_ACCOUNT_NAME:-${LIST_ACCOUNTS:-$NEW_ACCOUNT_NAME}}" ]&&_short_help
[ -n "${DELETE_ACCOUNT_NAME:-${LIST_ACCOUNTS-}}" ]&&exit 0
[ -n "$NEW_ACCOUNT_NAME" ]&&CONTINUE_WITH_NO_INPUT="true"
}
return 0
}
_setup_traps(){
_cleanup(){
[ -n "$SUPPORT_ANSI_ESCAPES" ]&&printf "\033[?25h\033[?7h"
{
[ -f "${TMPFILE}_ACCESS_TOKEN" ]&&{
. "${TMPFILE}_ACCESS_TOKEN"
export ACCESS_TOKEN ACCESS_TOKEN_EXPIRY INITIAL_ACCESS_TOKEN ACCOUNT_NAME
[ "$INITIAL_ACCESS_TOKEN" = "$ACCESS_TOKEN" ]||{
_update_config "ACCOUNT_${ACCOUNT_NAME}_ACCESS_TOKEN" "$ACCESS_TOKEN" "$CONFIG"
_update_config "ACCOUNT_${ACCOUNT_NAME}_ACCESS_TOKEN_EXPIRY" "$ACCESS_TOKEN_EXPIRY" "$CONFIG"
}
}||: 1>|/dev/null
[ -n "$ACCESS_TOKEN_SERVICE_PID" ]&&{
token_service_pids="$(ps --ppid="$ACCESS_TOKEN_SERVICE_PID" -o pid=)"
kill "$ACCESS_TOKEN_SERVICE_PID"
}||: 1>|/dev/null
script_children_pids="$(ps --ppid="$MAIN_PID" -o pid=)"
kill $token_service_pids $script_children_pids 1>|/dev/null
rm -f "${TMPFILE:?}"*
export abnormal_exit&&if [ -n "$abnormal_exit" ];then
printf "\n\n%s\n" "Script exited manually."
kill "${_SCRIPT_KILL_SIGNAL:--9}" -$$&
else
{ _cleanup_config "$CONFIG"&&[ "${GDL_INSTALLED_WITH-}" = script ]&&_auto_update;} 1>|/dev/null&
fi
} 2>|/dev/null||:
return 0
}
trap 'abnormal_exit="1" ; exit' INT TERM
trap '_cleanup' EXIT
trap '' TSTP
export MAIN_PID="$$"
}
_process_arguments(){
export DRY_RUN FOLDERNAME TOTAL_INPUTS PARALLEL_DOWNLOAD
[ -n "$FOLDERNAME" ]&&mkdir -p -- "$FOLDERNAME"
cd -- "${FOLDERNAME:-.}" 2>|/dev/null 1>&2||exit 1
_SEEN="" index_process_arguments=0
TOTAL_INPUTS="$((TOTAL_INPUTS<0?0:TOTAL_INPUTS))"
until [ "$index_process_arguments" -eq "$TOTAL_INPUTS" ];do
FILE_ID="" FOLDER_ID="" NAME="" FILE_MIME_TYPE="" SIZE=""
_set_value i FILE_ID "INPUT_ID_$((index_process_arguments+=1))"
case "$_SEEN" in
*"$FILE_ID"*)continue;;
*)_SEEN="$_SEEN$FILE_ID"
esac
_check_id "$FILE_ID"||continue
[ "$DRY_RUN" = "true" ]&&{
_clear_line 1
if [ -n "$FOLDER_ID" ];then
_print_center "justify" "Name: $NAME" " | $FOLDER_ID" "="
else
_print_center "justify" "Name: $NAME" " | $FILE_ID | Size: $({ [ -n "$SIZE" ]&&_bytes_to_human "$SIZE";}||printf 'Unknown')" "="
fi
printf '\n'&&continue
}
if [ -n "$FOLDER_ID" ];then
_download_folder "${DOWNLOAD_METHOD:-alt}" "$FOLDER_ID" "$NAME" "$PWD" "${PARALLEL_DOWNLOAD-}"
else
_download_file_main noparse "$FILE_ID" "$NAME" "$FILE_MIME_TYPE" "$SIZE"
fi
done
return 0
}
_main_helper(){
_setup_arguments "$@"||exit 1
"${SKIP_INTERNET_CHECK:-_check_internet}"||exit 1
TMPFILE="$(command -v mktemp 1>|/dev/null&&mktemp -u)"||TMPFILE="$(pwd)/.$(_t="$(_epoch)"&&printf "%s\n" "$((_t*_t))").tmpfile"
export TMPFILE
_setup_traps
if [ -n "$OAUTH_ENABLED" ];then
"$EXTRA_LOG" "justify" "Checking credentials.." "-"
{ _check_credentials&&_clear_line 1;}||{ "${QUIET:-_print_center}" "normal" "[ Error: Credentials checking failed ]" "="&&exit 1;}
"${QUIET:-_print_center}" "normal" " Account: $ACCOUNT_NAME " "="
export API_REQUEST_FUNCTION="_api_request_oauth" OAUTH_ENABLED="true"
else
export API_REQUEST_FUNCTION="_api_request"
fi
[ -n "$CONTINUE_WITH_NO_INPUT" ]&&exit 0
START="$(_epoch)"
[ -n "$SUPPORT_ANSI_ESCAPES" ]&&printf "\033[?25l"
_process_arguments
END="$(_epoch)"
DIFF="$((END-START))"
"${QUIET:-_print_center}" "normal" " Time Elapsed: ""$((DIFF/60))"" minute(s) and ""$((DIFF%60))"" seconds. " "="
}
set +a
main(){
[[ $# == 0 ]]&&{
printf "No valid arguments provided, use -h/--help flag to see usage.\n"
exit 0
}
[[ -z $SELF_SOURCE ]]&&{
export UTILS_FOLDER="${UTILS_FOLDER:-$PWD}"
export COMMON_PATH="${COMMON_UTILS_FILE:-$PWD}/../common"
{ . "$UTILS_FOLDER/common-utils.bash"&&. "$COMMON_PATH/parser.sh"&&. "$COMMON_PATH/flags.sh"&&. "$COMMON_PATH/auth-utils.sh"&&. "$COMMON_PATH/common-utils.sh"&&. "$COMMON_PATH/drive-utils.sh"&&. "$COMMON_PATH/download-utils.sh"&&. "$COMMON_PATH/gdl-common.sh";}||{ printf "Error: Unable to source util files.\n"&&exit 1;}
}
export SOURCE_UTILS=""
[[ ${BASH_VERSINFO:-0} -ge 4 ]]||{ printf "Bash version lower than 4.x not supported.\n"&&return 1;}
set -o noclobber -o pipefail||exit 1
export _SCRIPT_KILL_SIGNAL="--"
_main_helper "$@"||exit 1
}
{ [[ -z $SOURCED_GDL ]]&&main "$@";}||:
