Created
January 19, 2026 14:27
-
-
Save craigderington/c30f7237be9499b6af60f855435e5d0b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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