The bash script below will download all users gists from https://api.github.com/users/<github-username>/gists
and need the GitHub username
and GitHub API token as the rate limit for unauthenticated requests is 👎
# Unauthenticated
{
"rate": {
"limit": 60,
"remaining": 59,
"reset": 1704592325,
"used": 1,
"resource": "core"
}
}
# Authenticated
{
"rate": {
"limit": 5000,
"used": 0,
"remaining": 5000,
"reset": 1704592470
}
}
- Create a bash script using the code below
- Make the script executable by using the command
chmod +x export_gists.sh
- Create a GitHub API token in your GitHub settings and only enable the
gists
permission - Run the script with
./export_gists.sh
(E.g.,./export_gists.sh bulletinmybeard *******
)
#!/bin/bash
# Define the timezone offset from UTC (in hours)
timezone_offset=1
# Check if a username and bearer token are provided as arguments
if [ -z "$1" ] || [ -z "$2" ]; then
printf "Error: Missing arguments!\nUsage: %s <github-username> <bearer-token>" "$0"
exit 1
fi
# Assign the provided username and bearer token to variables
username="$1"
bearer_token="$2"
# Create a directory based on the username if it doesn't exist
export_dir="export_${username}"
mkdir -p "$export_dir"
# cURL helper function
run_curl_cmd() {
local url=$1
curl -sS \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${bearer_token}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"$url"
}
# Fetch and process the rate limit info
fetch_rate_limit() {
rate_limit_url="https://api.github.com/rate_limit"
response=$(run_curl_cmd "$rate_limit_url")
echo "$response" | jq '.rate'
}
convert_timestamp_to_date() {
local timestamp=$1
# Use date command to convert the UNIX timestamp
# '%F %T' will output the date in 'YYYY-MM-DD HH:MM:SS' format
date -r "$timestamp" '+%F %T'
}
calculate_time_until_reset() {
local reset_timestamp=$1
# Get the current time in Unix timestamp
current_timestamp=$(date +%s)
# Calculate the difference in seconds
diff_seconds=$((reset_timestamp - current_timestamp))
# Check if the difference is negative (reset time has passed)
if [ $diff_seconds -lt 0 ]; then
echo "The reset time has already passed."
return
fi
# Convert the difference to hours, minutes, and seconds
hours=$(printf "%02d" $((diff_seconds / 3600)))
minutes=$(printf "%02d" $(( (diff_seconds % 3600) / 60 )))
seconds=$(printf "%02d" $(( diff_seconds % 60 )))
echo "${hours}:${minutes}:${seconds}"
}
rate_limit_info=$(fetch_rate_limit)
request_limit=$(echo "$rate_limit_info" | jq '.limit')
remaining_requests=$(echo "$rate_limit_info" | jq '.remaining')
limit_reset=$(echo "$rate_limit_info" | jq '.reset')
limit_reset_datetime=$(convert_timestamp_to_date "$limit_reset")
time_until_reset=$(calculate_time_until_reset "$limit_reset")
# Check the current usage
if [ "$remaining_requests" -ne 0 ]; then
printf "\nYou have %s/%s remaining API requests\n=================================================\n" "$remaining_requests" "$request_limit"
else
echo "You hit the API request limit ($request_limit). Limit will reset in: $time_until_reset ($limit_reset_datetime)"
exit 0
fi
# Adjust adjust the local timestamp for CET to UTC
adjust_for_cet_to_utc() {
local timestamp=$1
local offset_seconds=$((timezone_offset * 3600))
echo "$timestamp - $offset_seconds"
}
# Fetch and process paginated gists
fetch_paginated_gists() {
local page=$1
local url="https://api.github.com/users/${username}/gists?page=${page}"
# Fetch the gists for the current page using the Bearer token
gists=$(run_curl_cmd "$url")
# Count the number of gists in the response
gist_count=$(echo "$gists" | jq '. | length')
# Check if the response is empty
if [ "$gist_count" -eq 0 ]; then
echo "end"
fi
# Process the gists
echo "$gists" | jq -r '.[] | {url: .files | to_entries[] | .value.raw_url, updated_at} | @base64' | \
while IFS= read -r line; do
# Decode the JSON string
json=$(echo "$line" | base64 -D)
# Extract the URL and updated_at value
url=$(echo "$json" | jq -r '.url')
updated_at=$(echo "$json" | jq -r '.updated_at')
# Convert updated_at to seconds since Unix epoch (UTC)
updated_at=$(date -jf "%Y-%m-%dT%H:%M:%SZ" "$updated_at" +%s)
# Extract filename and create a path within the export directory
filename=$(basename "$url")
file_path="${export_dir}/${filename}"
# Check if the file exists
if [ -f "$file_path" ]; then
# Get the last modification time of the local file in seconds since Unix epoch (local time)
local_updated_at=$(date -r "$file_path" +%s)
# Adjust local file timestamp from CET to UTC
local_updated_at=$(adjust_for_cet_to_utc $local_updated_at)
local_updated_at_int=$((local_updated_at))
updated_at_int=$((updated_at))
# Download the file if the local copy is older
if [ "$local_updated_at_int" -lt "$updated_at_int" ]; then
echo "Updating $file_path as it is older than the remote version."
curl -sS -o "$file_path" "$url"
else
echo "$file_path is up to date."
fi
else
echo "Downloading new file: $file_path"
curl -sS -o "$file_path" "$url"
fi
done
}
# Main loop to iterate over gist pages
page=1
while true; do
page_result=$(fetch_paginated_gists "$page")
if [[ -n "$page_result" ]] && [[ "$page_result" != *"end"* ]]; then
printf "\nProcessing Page #%s\n-------------------\n" "$page"
echo "$page_result"
((page++))
else
printf "\nAll gists have been processed!"
break
fi
done
./export_gists.sh bulletinmybeard **********
You have 4719/5000 remaining API requests
=================================================
Processing Page #1
-------------------
export_bulletinmybeard/list-network-connections-and-transform-them-into-json.md is up to date.
export_bulletinmybeard/chat.openai.com-userscript.js is up to date.
export_bulletinmybeard/fix-cannot-connect-to-the-docker-daemon-error-on-macoslinux.md is up to date.
export_bulletinmybeard/bol.com-userscript.js is up to date.
export_bulletinmybeard/debug-python-apps-via-docker-composeyml-in-pycharm.md is up to date.
export_bulletinmybeard/local-nginx-server-site-with-valid-ssl-certificate.md is up to date.
export_bulletinmybeard/python-script-to-alter-file-creation-date-from-filename.md is up to date.
export_bulletinmybeard/macos-prevent-flux-from-automatically-toggling-light-and-dark-mode.md is up to date.
export_bulletinmybeard/change-default-login-shell-on-macos-ventura.md is up to date.
export_bulletinmybeard/customize-default-syntax-highlighter-in-atom-editor-macos--linux.md is up to date.
export_bulletinmybeard/list-installed-homebrew-packages-in-tree-view-macos.md is up to date.
export_bulletinmybeard/delete-all-node_modules-folders-recursively.md is up to date.
export_bulletinmybeard/resolve-tabnine-subscription-sync-issues-in-your-ide.md is up to date.
export_bulletinmybeard/using-prompt-eol-mark-to-remove-extra-trailing-mark-in-terminal-output.md is up to date.
export_bulletinmybeard/capture-audio-file-loudness-levels-with-ffmpeg-perl-regex-and-jq.md is up to date.
export_bulletinmybeard/change-bookmark-icons-in-chrome-desktop-with-the-favicon-changer-in-2023.md is up to date.
export_bulletinmybeard/sitemap-xml-location-for-custom-medium-blogs.md is up to date.
export_bulletinmybeard/macos-toggle-google-chrome-swipe-navigation.md is up to date.
export_bulletinmybeard/put-io-move-to-folder-modal-input-search-filter.md is up to date.
export_bulletinmybeard/accessing-private-aws-cloud-resources-from-your-local-machine.md is up to date.
export_bulletinmybeard/git-log-json-output.md is up to date.
export_bulletinmybeard/prowritingaid-com-auto-expand-menu-from-the-go.md is up to date.
export_bulletinmybeard/reset-macos-notifications.md is up to date.
export_bulletinmybeard/tinder-auto-like-userscript.md is up to date.
export_bulletinmybeard/macos-kill-audio-command.md is up to date.
export_bulletinmybeard/fix-virtualbox-docker-machine-host-issues.md is up to date.
export_bulletinmybeard/run-screensaver-delayed-in-termnial.md is up to date.
export_bulletinmybeard/use-redis-in-lua-script-nginx.md is up to date.
export_bulletinmybeard/fix-for-sudo-command-error-unable-to-initialize-pam-no-such-file-or-directory.md is up to date.
export_bulletinmybeard/enforce-macos-icloud-sync.md is up to date.
Processing Page #2
-------------------
export_bulletinmybeard/patching-macos-apps-with-working-and-valid-app-signature.md is up to date.
export_bulletinmybeard/list-of-user-agents.md is up to date.
export_bulletinmybeard/quick-guide-publish-npm-packages.md is up to date.
export_bulletinmybeard/content-scraping-with-browser-devtools.js.md is up to date.
export_bulletinmybeard/list-first-level-package-details.js.md is up to date.
export_bulletinmybeard/automatic-content-updates-in-a-running-ios-simulator-instance.md is up to date.
export_bulletinmybeard/disable-the-git-integration-in-visual-studio-code.md is up to date.
export_bulletinmybeard/sublime-text-3-user-settings.md is up to date.
export_bulletinmybeard/visual-studio-code-user-settings-json.md is up to date.
All gists have been processed!