Skip to content

Instantly share code, notes, and snippets.

@tmatzxzone
Forked from Zorg64/download_gofile.sh
Last active December 5, 2024 17:15
Show Gist options
  • Save tmatzxzone/4a3b963f787a434f00101ab52c3c8b87 to your computer and use it in GitHub Desktop.
Save tmatzxzone/4a3b963f787a434f00101ab52c3c8b87 to your computer and use it in GitHub Desktop.
Bash script to download files from gofile.io
#!/bin/bash
# Prompts the user for a URL if not provided as a command-line argument.
# Extracts the ID from the given URL to use in API requests.
function promptForURL() {
local url="$1"
until [ -n "$url" ]; do
read -p "URL: " url
done
id=$(sed 's|.*gofile.io/d/||g' <<< "$url")
echo -n "Loading $id content..."
}
# Ur own token without creating guest acc
function retrieveToken() {
token="your_token_here"
}
# Retrieves a website token required for some API requests.
function retrieveWebsiteToken() {
websiteToken=$(curl -s 'https://gofile.io/dist/js/global.js' | awk -F'"' '/appdata\.wt = "/ {print $(NF-1)}')
if [ -z "$websiteToken" ]; then
echo "Failed to retrieve website token. Please try again later."
exit 1
fi
}
# Retrieve content from GoFile using the content ID.
# If a password is required, prompts the user for it.
function retrieveContent() {
local password_hash="$1"
local extra_params=""
if [ -n "$password_hash" ]; then
extra_params="&password=$password_hash"
fi
resp=$(curl -H "Authorization: Bearer $token" "https://api.gofile.io/contents/$id?wt=$websiteToken&cache=true$extra_params" 2>/dev/null)
local status=$(jq -r '.status' <<< "$resp")
local notFound=$(jq -r '.data.notFound // "false"' <<< "$resp")
local passwordRequired=$(jq -r '.data.password // "false"' <<< "$resp")
local passwordStatus=$(jq -r '.data.passwordStatus // "none"' <<< "$resp")
if [[ "$notFound" == "true" ]]; then
printf "\r\033[K"
echo "Content not found. Please check the URL and try again."
exit 1
elif [[ "$status" == "ok" && "$passwordRequired" == "true" && "$passwordStatus" == "passwordRequired" && -z "$password_hash" ]]; then
handlePassword
elif [[ "$status" == "ok" && "$passwordRequired" == "true" && "$passwordStatus" != "passwordOk" ]]; then
printf "\r\033[K"
echo "Incorrect password provided. Please try again."
exit 1
elif [[ "$status" != "ok" ]]; then
printf "\r\033[K"
echo "Failed to retrieve content. Please check the URL or try again later."
exit 1
fi
}
# Prompts the user for a password if needed to access protected content.
function handlePassword() {
printf "\r\033[K"
read -sp "Enter password: " password
echo
password_hash=$(printf "%s" "$password" | sha256sum | cut -d' ' -f1)
retrieveContent "$password_hash"
}
# Shows a spinner animation while background processes are running.
function spinner {
local -r pid=$1
local -r delay=0.2
local spinstr='|/-\'
tput civis # Hide cursor
echo -n " "
while kill -0 $pid 2>/dev/null; do
local temp=${spinstr#?}
printf "\b%c" "$spinstr"
local spinstr=$temp${spinstr%"$temp"}
sleep $delay
done
printf "\b "
tput cnorm # Show cursor
}
# Formats the size of the file from bytes to a more readable format (MB or GB).
function format_size {
local -i bytes=$1
if [ $bytes -lt 1000000000 ]; then
echo $(awk "BEGIN {printf \"%.2f\", $bytes/1000000}")" MB"
else
echo $(awk "BEGIN {printf \"%.2f\", $bytes/1000000000}")" GB"
fi
}
# Manages the stopping and starting of a spinner for background operations.
function start_and_stop_spinner() {
local -a pids=("${!1}")
spinner "${pids[0]}" &
spinner_pid=$!
# Waits for all processes to finish.
for pid in "${pids[@]}"; do
if [[ -n "$pid" && "$pid" =~ ^[0-9]+$ ]]; then
wait "$pid"
fi
done
# Stops the spinner if it's still running.
if kill -0 "$spinner_pid" 2>/dev/null; then
kill -9 "$spinner_pid"
wait "$spinner_pid" 2>/dev/null
fi
}
# Tracks download progress and updates the console.
function download_progress() {
local total_size=$1
local name=$2
local -a pids=("${!3}")
local current_size=0
local percent=0
# Ensures the reported total size is valid.
if [ "$total_size" -le 0 ]; then
echo "Error: Total size is invalid."
return
fi
tput civis
# Continuously updates progress until all parts are downloaded.
while : ; do
current_size=0
for part in "$name.part"*; do
if [ -f "$part" ]; then
local size=$(stat -c "%s" "$part")
current_size=$((current_size + size))
fi
done
percent=$((current_size * 100 / total_size))
printf "\r$name | $f_size | $percent%%"
# Checks if all download processes have finished.
local all_done=1
for pid in "${pids[@]}"; do
if kill -0 "$pid" 2>/dev/null; then
all_done=0
break
fi
done
[ "$all_done" -eq 1 ] && break
sleep 1
done
printf "\r\033[K"
tput cnorm
}
function determine_download_parts() {
local file_size=$1 # File size in bytes
if [ "$file_size" -le 50000000 ]; then
echo 1 # Files 50 MB or smaller
elif [ "$file_size" -gt 50000000 ] && [ "$file_size" -le 100000000 ]; then
echo 2 # Files larger than 50 MB up to 100 MB
else
echo 3 # Files larger than 100 MB
fi
}
function download_and_combine_file() {
local name=$1
local file_url=$2
local total_size=$3
local expected_md5=$4
local num_parts=$(determine_download_parts "$total_size") # Determine the number of parts
local -a pids=()
local f_size=$(format_size "$total_size")
echo -n "$name | $f_size | "
# Calculate the size of each part based on the total size and the number of parts
local part_size=$(($total_size / $num_parts))
local last_part_size=$(($total_size - ($part_size * ($num_parts - 1))))
# Download each part
for ((part=0; part<num_parts; part++)); do
local start=$(($part * $part_size))
local end=$(($start + $part_size - 1))
# Adjust the end for the last part
if [ $part -eq $(($num_parts - 1)) ]; then
end=$(($start + $last_part_size - 1))
fi
curl -s -H 'Cookie: accountToken='"$token" -H "Range: bytes=$start-$end" "$file_url" -o "$name.part$part" &
pids[${part}]=$!
done
# Monitors download progress.
download_progress "$total_size" "$name" "pids[@]"
echo "$name | $f_size | 100%"
echo -n "Combining parts... "
# Combines parts and calculates MD5 checksum in the background
(
for ((part=0; part<num_parts; part++)); do
cat "$name.part$part" >> "$name" # Appends each part in sequence
done
# Remove part files after combining
for ((part=0; part<num_parts; part++)); do
rm -f "$name.part$part"
done
# Calculating MD5 checksum of the combined file
calculated_md5=$(md5sum "$name" | awk '{print $1}')
echo $calculated_md5 > "$name.md5"
) &
combine_pid=$!
# Handles the spinner for the combining and MD5 calculation process.
local -a combine_pids=($combine_pid)
start_and_stop_spinner "combine_pids[@]"
printf "\r\033[K"
# Read the calculated MD5 from the file
calculated_md5=$(<"$name.md5")
# Comparing checksums
if [ "$calculated_md5" != "$expected_md5" ]; then
echo "Combining parts... Error! Download corrupt, removing '$name'"
rm -f "$name"
failed_dl+=("$name")
rm -f "$name.md5"
return 1
else
echo "Combining parts... Done!"
fi
rm -f "$name.md5"
}
# Processes each file found within the content fetched from GoFile.
function processFiles() {
# Extracts names and links for all files within the content and sorts them alphabetically.
while IFS="|" read -r name total_size file_url md5_checksum; do
if [ ! -f "$name" ]; then
if ! [[ $total_size =~ ^[0-9]+$ ]]; then
echo "Error: Failed to get valid content length for \"$name\""
continue
fi
download_and_combine_file "$name" "$file_url" "$total_size" "$md5_checksum"
fi
done < <(jq -r '.data.children[] | "\(.name)|\(.size)|\(.link)|\(.md5)"' <<< "$resp" | sort -t "|" -k1,1)
}
#Main
# Initiates the script by prompting the user for a URL if not supplied as an argument.
promptForURL "$1"
# Retrieves a token for authentication with the GoFile API.
retrieveToken
# Retrieves a website token required for further API interactions.
retrieveWebsiteToken
# Fetch content info from GoFile using the ID extracted from the URL.
retrieveContent
mkdir -p "$id"
cd "$id"
printf "\r\033[K"
echo "Loading $id content...✓"
# Processes files within the fetched content.
failed_dl=()
processFiles
# Show any failed downloads
echo
if [ ${#failed_dl[@]} -ne 0 ]; then
echo "Failed Downloads: ${#failed_dl[@]}"
for file in "${failed_dl[@]}"; do
echo "- $file"
done
echo -e "\nRun script again to attempt failed files.\n"
else
echo -e "All downloads successful.\n"
fi
echo -e "\nNote: gofile.io is entirely free with no ads,\nYou can support it at https://gofile.io/donate"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment