Skip to content

Instantly share code, notes, and snippets.

@knzai
Last active July 15, 2024 18:42
Show Gist options
  • Save knzai/75702a336a25646e6c0039f96d5732b9 to your computer and use it in GitHub Desktop.
Save knzai/75702a336a25646e6c0039f96d5732b9 to your computer and use it in GitHub Desktop.
curlable bash script to grab google drive file exports from their api, eg grabbing pdfs of gdocs
#!/usr/bin/env bash
set -Eeo pipefail
#============================
# CONSTANTS & DEFAULTS
#============================
#constants
readonly VERSION_NUM='1.2.0'
readonly SCRIPT='ggdrive.sh'
#in case terminal doesn't support colors - readonly after setup_colors runs
RESET='' RED='' GREEN='' BLUE='' PURPLE='' CYAN='' YELLOW=''
#environment variables
#G_API_KEY
#IFS # shell built-in Internal Field Separator
#defaults
#unset csv_file
export=false
g_api='https://www.googleapis.com/drive/v2'
tempfile='tempfile'
user_agent='gist.github.com/knzai/75702a336a25646e6c0039f96d5732b9'
#============================
# USAGE & METADATA
#============================
usage() {
cat <<-EOF
${CYAN}Name:${RESET} $(script_name) ($VERSION_NUM)
${CYAN}Description:${RESET} Download google drive file exports, eg gdocs -> pdf
${CYAN}Usage:${RESET}
${RED}<G_API_KEY=XXXX>${RESET} ./$(script_name) ${YELLOW}[-h, --help] [-v] [-e] [-g ${RED}<g_api>${YELLOW}] [-t ${RED}<tempfile>${YELLOW}] [-u ${RED}<user_agent>${YELLOW}] [csv_file]${RESET}
EOF
for i in "$@"; do
case $i in
vars) cat <<-EOF
${CYAN}Environoment variables:${RESET}
${RED}G_API_KEY${RESET} REQUIRED Google Cloud API Key with access to Google Drive API
${CYAN}Arguments:${RESET}
${YELLOW}[csv_file]${RESET} Path/to/file.csv. Leave blank for NOOP.
${CYAN}Flags:${RESET}
${YELLOW}[-e, --export]${RESET} Export functions. Use w/o [csv_file] for custom handling
${YELLOW}[-v, --version] ${RESET} Output version info. Long form provides more metadata
${YELLOW}[-h, --help]${RESET} Output help. Long form provides more info, examples
${CYAN}Options${RESET}
${BLUE}#Specify endpoint of the google drive api${RESET}
${YELLOW}[-g, --g_api] ${RED}<arg>${RESET} {'https://www.googleapis.com/drive/v2'}
${BLUE}#If you want to be particular about the temporary file${RESET}
${YELLOW}[-t, --tempfile] ${RED}<arg>${RESET} {tempfile}
${BLUE}#I don't think Google actually cares, but hey${RESET}
${YELLOW}[-u, --user_agent] ${RED}<arg>${RESET} {'gist.github.com/knzai/75702a336a25646e6c0039f96d5732b9'}
EOF
shift ;;
eg) cat <<-EOF
${CYAN}Examples${RESET}
${BLUE}# Standard usage${RESET}
./$(script_name) path/to/csv
${BLUE}# Do nothing except export functions for your own use${RESET}
./$(script_name) -e
${BLUE}# Specify a different version of the google drive api${RESET}
./$(script_name) -g https://www.googleapis.com/drive/v3 path/to/csv
${CYAN}Curl examples${RESET}
${BLUE}#standard run directly from the pipe
curl -s -L https://gist.github.com/knzai/75702a336a25646e6c0039f96d5732b9/raw | bash -s -- gdrive_files.csv
${BLUE}#only download if it doesn't exist, then run it${RESET} - script_name harcoded for ease of copying from gist. Update if needed
[ -f ggdrive.sh ] || curl -s -L https://gist.github.com/knzai/75702a336a25646e6c0039f96d5732b9/raw > ggdrive.sh && bash ggdrive.sh gdrive_files.csv
${BLUE}#my fave bootstrapping: if there isn't a tempfile, download to one and run; easy csv_file path at front${RESET}
csv_file=gdrive_files.csv && [[ -f \$ggdrivetemp || ggdrivetemp=\$(mktemp -t ggdriveXXXXXXXXXX.sh) ]] \\
&& [[ -s \$ggdrivetemp ]] || curl -s -L https://gist.github.com/knzai/75702a336a25646e6c0039f96d5732b9/raw \\
> \$ggdrivetemp && bash \$ggdrivetemp \$csv_file
EOF
shift ;;
esac
done
}
version() {
msg "$(script_name) $VERSION_NUM"
if [ ! $# -eq 0 ]; then
cat <<-EOF
${CYAN}Authour & Copyright:${RESET}
${BLUE}version${RESET} $(script_name) $VERSION_NUM
${BLUE}author${RESET} Kenzi Connor
${BLUE}copyright${RESET} Copyright (c) Public Domain
${BLUE}license${RESET} Public Domain via Unlicense (see footer)
${BLUE}site${RESET} knz.ai/ggdrive
${BLUE}source${RESET} gist.github.com/knzai/75702a336a25646e6c0039f96d5732b9
${CYAN}Version history:${RESET}
${BLUE}2024/07/10${RESET} : 0.0.1 : Script creation
${BLUE}2024/07/11${RESET} : 0.0.2 : Cleaned up, comment, add help and usage
${BLUE}2024/07/12${RESET} : 0.0.3 : Simplify usage() to make curling easier
${BLUE}2024/07/12${RESET} : 1.0.0 : BREAKING Rename env var for clarity
${BLUE}2024/07/12${RESET} : 1.1.0 : Changed --help and --version usage
${BLUE}2024/07/13${RESET} : 1.2.0 : More usage() improvements
EOF
fi
}
#============================
# MESSAGING & COLORS
#============================
die() { echo "$*" >&2; exit 2; }
msg() { echo >&2 -e "${1-}"; }
script_name() { echo "${GREEN}$SCRIPT${RESET}"; }
setup_colors() {
if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then
RESET=$(tput setaf 7) RED=$(tput setaf 1) GREEN=$(tput setaf 2) BLUE=$(tput setaf 4) CYAN=$(tput setaf 6) YELLOW=$(tput setaf 3)
fi
readonly RESET RED GREEN BLUE PURPLE CYAN YELLOW
}
#============================
# PARSE PARAMETERS
#============================
parse_params() {
if [ $# -eq 0 ]; then usage && exit; fi;
#flags and options
while getopts eg:t:u:hv-: OPT; do
# support long options: https://stackoverflow.com/a/28466267/519360
if [ "$OPT" = "-" ]; then # long option: reformulate OPT and OPTARG
OPT="${OPTARG%%=*}" # extract long option name
OPTARG="${OPTARG#"$OPT"}" # extract long option argument (may be empty)
OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=`
fi
case "$OPT" in
e|export ) export=true;;
g|g_api ) g_api="$OPTARG";;
t|tempfile ) tempfile="$OPTARG";;
u|user_agent) user_agent="$OPTARG";;
h ) usage 'vars' ;;
help ) usage 'vars' 'eg' ;;
v ) version ;;
version ) version 'full' ;;
* ) exit 2;;
esac
done
shift $((OPTIND-1)) # remove parsed options and args from $@ list
#positional args
csv_file=$1
return 0
}
#============================
# ALIASES AND FUNCTIONS
#============================
get_gdrive_files() {
if [ ! -f $1 ]; then die "$1 file not found"; fi
oldifs=$IFS
IFS=','
while read gd_id mime dest min_size
do
gdrive_export $gd_id $mime
replace_if_valid $dest $min_size
done < $1
IFS=$oldifs
}
gdrive_export() {
#$1: google_file_id
#$2: mime_type
wget -nv -O $tempfile --user-agent=$user_agent "$g_api/files/$1/export?mimeType=$2&key=$G_API_KEY"
}
replace_if_valid() {
#$1: dest
#$2: min_size
if [ $(du -k $tempfile | cut -f1) -gt $2 ]; then
mv $tempfile "$1"
else
die "Problem fetching file"
fi
}
#============================
# MAIN
#============================
main() {
if [ $csv_file ]; then
get_gdrive_files $csv_file
elif $export; then
export -f get_gdrive_files
export -f gdrive_export
export -f replace_if_valid
fi
}
setup_colors
parse_params "$@"
main
#===============================================================================
# LICENSE: Public Domain via Unlicense
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>
@knzai
Copy link
Author

knzai commented Jul 12, 2024

Maybe I'll crack the curl usage without having to pipe into a tempfile (head calls used to parse the usage info easier with a file to aim it at), or at least make and cleanup the tmpfile within the script if called from a pipe. But not today.

ETA: Or I'll just strip out the complexity for a simple usage() function instead, which I did.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment