#!/usr/bin/env bash
set -e
VERSION=0.1
LOGIN_PAGE=https://www.humblebundle.com/login
HOME_PAGE=https://www.humblebundle.com/home
COOKIE_JAR=
FILE=
DESTINATION=
DOWNLOAD=1
USERNAME=
PASSWORD=
KEYS=()
STORAGE=
login() {
/usr/bin/curl -s --cookie-jar "$COOKIE_JAR" \
--data "username=$USERNAME" --data "password=$PASSWORD" "$LOGIN_PAGE"
}
discover_url() {
local LISTING_PAGE="$1"
/usr/bin/curl -s --cookie "$COOKIE_JAR" "$LISTING_PAGE" | grep "/$FILE?" | \
sed -e "s/.* data-web='\([^']*\)'.*/\1/" | head -n 1
}
usage() {
echo "hib-dlagent $VERSION"
echo "Tool to download Humble Indie Bundle binaries by file name"
echo
echo "Usage: $0 [OPTIONS] FILE"
echo "Options:"
echo " -d
Directory for searching and saving files. The normal save"
echo " location is still used, but will be a symbolic link"
echo " -h This help"
echo " -k Search key's files. Use multiple times for multiple keys"
echo " -o Name to use when saving file"
echo " -p Use pass to login. If specified multiple times, the last is"
echo " used"
echo " -s Print URL to stdout instead of downloading. Incompatible"
echo " with -d"
echo " -u Use user to login. Search account's files. If specified"
echo " multiple times, the last is used"
echo
echo "If you specify -u, then all of that account's bundles are searched. If"
echo "a key is associated with a HIB account then you must use -u/-p, since"
echo "that key only works when logged into that account. It is not helpful to"
echo "specify -k for bundles associated with an account."
}
handle_download() {
local SAVE_FILE="$1"
local LISTING_PAGES=()
COOKIE_JAR=$(mktemp)
if [ -n "$USERNAME" ]; then
login
LISTING_PAGES+=("$HOME_PAGE")
fi
for KEY in "${KEYS[@]}"; do
LISTING_PAGES+=("https://www.humblebundle.com/downloads?key=$KEY")
done
if [ -z "$LISTING_PAGES" ]; then
echo "You must specify at least one of -u and -k" >&2
exit 1
fi
local URL
for LISTING_PAGE in "${LISTING_PAGES[@]}"; do
URL=$(discover_url "$LISTING_PAGE")
if [ -n "$URL" ]; then break; fi
done
# Cookie no longer necessary.
rm "$COOKIE_JAR"
if [ ! -n "$URL" ]; then
echo "Could not find URL for file: $FILE" >&2
exit 2
fi
if [ $DOWNLOAD -eq 0 ]; then
echo "$URL"
else
/usr/bin/curl -C - --retry 3 --retry-delay 3 -o "$SAVE_FILE" "$URL"
fi
}
main() {
if [ $# -eq 0 ]; then
usage
exit 1
fi
while getopts "hd:k:o:p:su:" opt; do
case $opt in
\?)
exit 1
;;
h)
usage
exit 1
;;
d)
STORAGE="$OPTARG"
;;
k)
KEYS+=("$OPTARG")
;;
o)
DESTINATION="$OPTARG"
;;
p)
PASSWORD="$OPTARG"
;;
s)
DOWNLOAD=0
;;
u)
USERNAME="$OPTARG"
;;
esac
done
shift $(($OPTIND - 1))
if [ $# == 0 ]; then
echo "Missing argument FILE" >&2
exit 1
fi
if [ $# != 1 ]; then
echo "Unexpected argument: $2" >&2
exit 1
fi
if [ $DOWNLOAD -eq 0 -a -n "$STORAGE" ]; then
echo "-s and -d are incompatible" >&2
exit 1
fi
FILE="$1"
if [ "$FILE" != "$(basename "$FILE")" ]; then
# We need a simple file name without any slashes. Instead of erroring, we
# strip the file name out so that hib://filename is a valid argument.
FILE=$(basename "$FILE")
# Since we are doing something fancy, give the user a clue that we modified
# their input.
echo "Searching for $FILE" >&2
fi
if [ -z "$DESTINATION" ]; then
DESTINATION="."
fi
if [ -d "$DESTINATION" ]; then
DESTINATION="$DESTINATION/$FILE"
fi
if [ -z "$STORAGE" ]; then
handle_download "$DESTINATION"
else
local STORAGE_FILE
STORAGE_FILE=$(/usr/bin/find "$STORAGE" -name "$FILE")
if [ -z "$STORAGE_FILE" ]; then
STORAGE_FILE="$STORAGE/$FILE"
handle_download "$STORAGE_FILE"
fi
if [ ! "$STORAGE_FILE" -ef "$DESTINATION" ]; then
ln -s "$STORAGE_FILE" "$DESTINATION"
if [ ! "$STORAGE_FILE" -ef "$DESTINATION" ]; then
# If DESTINATION is in a different directory than the CWD and STORAGE
# is a relative path, then ln -s will produce a broken link. To produce
# a valid link we resolve the path with readlink. This is unfortunate
# because having relative links is nicer and we will undo any symlinks
# in the path. Therefore, we detect when things have broken and only
# use readlink when we must.
STORAGE_FILE=$(/usr/bin/readlink -f "$STORAGE_FILE")
rm "$DESTINATION"
ln -s "$STORAGE_FILE" "$DESTINATION"
fi
fi
fi
}
main "$@"