Skip to content

Instantly share code, notes, and snippets.

@craigderington
Created January 19, 2026 14:27
Show Gist options
  • Select an option

  • Save craigderington/c30f7237be9499b6af60f855435e5d0b to your computer and use it in GitHub Desktop.

Select an option

Save craigderington/c30f7237be9499b6af60f855435e5d0b to your computer and use it in GitHub Desktop.
#!/bin/bash
# 🌩️ ULTIMATE WEATHER RADAR TERMINAL
# The most powerful terminal-based weather radar viewer
set -euo pipefail
# ============================================================================
# CONFIGURATION
# ============================================================================
declare -A RADARS=(
# National Views
["c"]="CONUS|National View|https://radar.weather.gov/ridge/standard/CONUS_loop.gif"
["n"]="NORTHEAST|Northeast US|https://radar.weather.gov/ridge/standard/NORTHEAST_loop.gif"
["s"]="SOUTHEAST|Southeast US|https://radar.weather.gov/ridge/standard/SOUTHEAST_loop.gif"
["w"]="CENTGRTLAKES|Great Lakes|https://radar.weather.gov/ridge/standard/CENTGRTLAKES_loop.gif"
["p"]="PACNORTHWEST|Pacific NW|https://radar.weather.gov/ridge/standard/PACNORTHWEST_loop.gif"
# Major Cities
["1"]="KMLB|Melbourne FL|https://radar.weather.gov/ridge/standard/KMLB_loop.gif"
["2"]="KMIA|Miami FL|https://radar.weather.gov/ridge/standard/KMIA_loop.gif"
["3"]="KJAX|Jacksonville FL|https://radar.weather.gov/ridge/standard/KJAX_loop.gif"
["4"]="KATL|Atlanta GA|https://radar.weather.gov/ridge/standard/KFFC_loop.gif"
["5"]="KNYC|New York City|https://radar.weather.gov/ridge/standard/KOKX_loop.gif"
["6"]="KCHI|Chicago IL|https://radar.weather.gov/ridge/standard/KLOT_loop.gif"
["7"]="KDFW|Dallas TX|https://radar.weather.gov/ridge/standard/KFWS_loop.gif"
["8"]="KDEN|Denver CO|https://radar.weather.gov/ridge/standard/KFTG_loop.gif"
["9"]="KSEA|Seattle WA|https://radar.weather.gov/ridge/standard/KATX_loop.gif"
["0"]="KLAX|Los Angeles CA|https://radar.weather.gov/ridge/standard/KSOX_loop.gif"
)
CURRENT="s"
TEMP="/tmp/radar.gif"
WEATHER_DATA="/tmp/radar_weather.json"
STATUS_FILE="/tmp/radar_status.txt"
MPV_PID=""
AUTO_REFRESH_PID=""
# Terminal colors
declare -A COLORS=(
["RESET"]="\e[0m"
["BOLD"]="\e[1m"
["DIM"]="\e[2m"
["RED"]="\e[31m"
["GREEN"]="\e[32m"
["YELLOW"]="\e[33m"
["BLUE"]="\e[34m"
["MAGENTA"]="\e[35m"
["CYAN"]="\e[36m"
["WHITE"]="\e[37m"
["BG_BLUE"]="\e[44m"
["BG_BLACK"]="\e[40m"
)
# ============================================================================
# TERMINAL MANAGEMENT
# ============================================================================
setup_terminal() {
# Hide cursor and disable echo
tput civis 2>/dev/null || true
stty -echo 2>/dev/null || true
# Clear screen
clear
}
cleanup_terminal() {
# Show cursor and enable echo
tput cnorm 2>/dev/null || true
stty echo 2>/dev/null || true
# Kill background processes
[[ -n "$MPV_PID" ]] && kill "$MPV_PID" 2>/dev/null || true
[[ -n "$AUTO_REFRESH_PID" ]] && kill "$AUTO_REFRESH_PID" 2>/dev/null || true
# Cleanup temp files
rm -f "$TEMP" "$WEATHER_DATA" "$STATUS_FILE" "$TEMP.new"
clear
}
trap cleanup_terminal EXIT INT TERM
# ============================================================================
# RENDERER DETECTION
# ============================================================================
detect_renderer() {
if [[ -n "${KITTY_WINDOW_ID:-}" ]]; then
echo "kitty"
elif [[ "$TERM" == "xterm-kitty" ]]; then
echo "kitty"
else
echo "tct"
fi
}
VO=$(detect_renderer)
# ============================================================================
# STATUS BAR & UI
# ============================================================================
get_radar_info() {
local key="$1"
local info="${RADARS[$key]}"
echo "$info" | cut -d'|' -f1,2
}
get_radar_url() {
local key="$1"
local info="${RADARS[$key]}"
echo "$info" | cut -d'|' -f3
}
draw_header() {
local radar_code=$(get_radar_info "$CURRENT" | cut -d'|' -f1)
local radar_name=$(get_radar_info "$CURRENT" | cut -d'|' -f2)
local timestamp=$(date '+%Y-%m-%d %H:%M:%S %Z')
echo -e "${COLORS[BG_BLUE]}${COLORS[WHITE]}${COLORS[BOLD]}"
echo -e "╔════════════════════════════════════════════════════════════════════════════════╗"
echo -e "║ ⚡ WEATHER RADAR TERMINAL ⚡ $timestamp ║"
echo -e "╠════════════════════════════════════════════════════════════════════════════════╣"
echo -e "║ 📡 Station: ${COLORS[YELLOW]}$radar_code${COLORS[WHITE]}${COLORS[BG_BLUE]} - $radar_name"
# Add spacing to align properly
local line_length=80
local current_length=$((14 + ${#radar_code} + 3 + ${#radar_name}))
local spaces_needed=$((line_length - current_length - 1))
printf "║ 📡 Station: ${COLORS[YELLOW]}%s${COLORS[WHITE]}${COLORS[BG_BLUE]} - %-${spaces_needed}s║\n" "$radar_code" "$radar_name"
echo -e "╠════════════════════════════════════════════════════════════════════════════════╣${COLORS[RESET]}"
}
draw_controls() {
echo -e "${COLORS[CYAN]}${COLORS[BOLD]}"
echo "╔══════════════════════════════════════════════════════════════════════════════════╗"
echo "║ 🎮 CONTROLS ║"
echo "╠══════════════════════════════════════════════════════════════════════════════════╣"
echo "║ ${COLORS[YELLOW]}REGIONS:${COLORS[CYAN]} [c]ONUS [n]ortheast [s]outheast [w]great lakes [p]acific NW ║"
echo "║ ${COLORS[YELLOW]}CITIES:${COLORS[CYAN]} [1]Melbourne [2]Miami [3]Jacksonville [4]Atlanta [5]NYC ║"
echo "║ [6]Chicago [7]Dallas [8]Denver [9]Seattle [0]Los Angeles ║"
echo "║ ${COLORS[YELLOW]}OTHER:${COLORS[CYAN]} [r]efresh now [h]elp [q]uit ║"
echo "╚══════════════════════════════════════════════════════════════════════════════════╝${COLORS[RESET]}"
}
show_loading() {
local message="${1:-Loading radar data...}"
echo -e "${COLORS[YELLOW]}⏳ $message${COLORS[RESET]}"
}
show_success() {
local message="${1:-Success!}"
echo -e "${COLORS[GREEN]}✓ $message${COLORS[RESET]}"
}
show_error() {
local message="${1:-Error occurred}"
echo -e "${COLORS[RED]}✗ $message${COLORS[RESET]}"
}
show_info() {
local message="$1"
echo -e "${COLORS[BLUE]}ℹ $message${COLORS[RESET]}"
}
update_status() {
tput sc 2>/dev/null || true # Save cursor position
tput cup 0 0 2>/dev/null || true # Move to top
draw_header
tput rc 2>/dev/null || true # Restore cursor position
}
# ============================================================================
# RADAR DATA MANAGEMENT
# ============================================================================
download_radar() {
local url=$(get_radar_url "$CURRENT")
local radar_name=$(get_radar_info "$CURRENT" | cut -d'|' -f2)
show_loading "Downloading $radar_name radar..."
if wget -q --timeout=10 -O "$TEMP" "$url" 2>/dev/null; then
show_success "Radar data updated"
return 0
else
show_error "Failed to download radar data"
return 1
fi
}
# ============================================================================
# MPV PLAYER MANAGEMENT
# ============================================================================
start_mpv() {
# Redirect all mpv output to /dev/null to prevent terminal pollution
mpv \
--vo="$VO" \
--loop=inf \
--scale=ewa_lanczossharp \
--dscale=ewa_lanczossharp \
--cscale=ewa_lanczossharp \
--interpolation=yes \
--tscale=oversample \
--video-sync=display-resample \
--no-config \
--no-osc \
--no-osd-bar \
--really-quiet \
--msg-level=all=no \
"$TEMP" </dev/null &>/dev/null &
MPV_PID=$!
# Give mpv a moment to start
sleep 0.5
}
restart_mpv() {
if [[ -n "$MPV_PID" ]]; then
kill "$MPV_PID" 2>/dev/null || true
wait "$MPV_PID" 2>/dev/null || true
fi
start_mpv
}
# ============================================================================
# AUTO-REFRESH BACKGROUND TASK
# ============================================================================
start_auto_refresh() {
(
while true; do
sleep 120 # Refresh every 2 minutes
local url=$(get_radar_url "$CURRENT")
if wget -q --timeout=10 -O "$TEMP.new" "$url" 2>/dev/null; then
mv "$TEMP.new" "$TEMP"
else
rm -f "$TEMP.new"
fi
done
) &
AUTO_REFRESH_PID=$!
}
# ============================================================================
# MAIN APPLICATION FLOW
# ============================================================================
show_welcome() {
clear
echo -e "${COLORS[CYAN]}${COLORS[BOLD]}"
echo "╔══════════════════════════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ⚡ ULTIMATE WEATHER RADAR TERMINAL ⚡ ║"
echo "║ ║"
echo "║ Live NOAA Weather Radar Viewer ║"
echo "║ ║"
echo "╚══════════════════════════════════════════════════════════════════════════════════╝"
echo -e "${COLORS[RESET]}\n"
show_info "Renderer: $VO"
show_info "Starting with Southeast US radar..."
echo ""
}
main() {
setup_terminal
show_welcome
# Initial download and start
if ! download_radar; then
show_error "Failed to initialize. Check your internet connection."
sleep 3
exit 1
fi
start_mpv
start_auto_refresh
echo ""
draw_controls
echo ""
show_info "Radar is now playing. Use the controls above to switch views."
echo ""
# Main input loop
while true; do
# Read single character without echo
IFS= read -rsn1 key
case "$key" in
c|n|s|w|p|1|2|3|4|5|6|7|8|9|0)
if [[ -n "${RADARS[$key]:-}" ]]; then
CURRENT="$key"
local radar_name=$(get_radar_info "$CURRENT" | cut -d'|' -f2)
echo ""
show_info "Switching to $radar_name..."
if download_radar; then
restart_mpv
# Kill and restart auto-refresh for new radar
[[ -n "$AUTO_REFRESH_PID" ]] && kill "$AUTO_REFRESH_PID" 2>/dev/null || true
start_auto_refresh
fi
fi
;;
r|R)
echo ""
show_info "Manual refresh requested..."
if download_radar; then
restart_mpv
fi
;;
h|H|\?)
echo ""
draw_controls
echo ""
;;
q|Q)
echo ""
show_info "Shutting down radar viewer..."
cleanup_terminal
exit 0
;;
esac
done
}
# ============================================================================
# ENTRY POINT
# ============================================================================
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment