mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-03-20 06:11:27 -07:00
168 lines
4.8 KiB
Bash
Executable File
168 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
location_input="${1:-Los_Angeles}"
|
|
location_query="${location_input//_/ }"
|
|
cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/waybar"
|
|
cache_key="${location_input//[^[:alnum:]_.-]/_}"
|
|
geo_cache_file="$cache_dir/weather-geo-${cache_key}.json"
|
|
weather_cache_file="$cache_dir/weather-${cache_key}.json"
|
|
|
|
json_escape() {
|
|
jq -Rsa .
|
|
}
|
|
|
|
emit_json() {
|
|
local text="$1"
|
|
local tooltip="$2"
|
|
|
|
printf '{"text":%s,"tooltip":%s}\n' \
|
|
"$(printf '%s' "$text" | json_escape)" \
|
|
"$(printf '%s' "$tooltip" | json_escape)"
|
|
}
|
|
|
|
emit_cached_or_error() {
|
|
if [[ -f "$weather_cache_file" ]]; then
|
|
cat "$weather_cache_file"
|
|
return
|
|
fi
|
|
|
|
emit_json "weather unavailable" "weather service unavailable"
|
|
}
|
|
|
|
url_encode() {
|
|
jq -rn --arg value "$1" '$value | @uri'
|
|
}
|
|
|
|
weather_icon() {
|
|
local code="$1"
|
|
local is_day="$2"
|
|
|
|
case "$code" in
|
|
0) [[ "$is_day" == "1" ]] && printf '☀' || printf '☾' ;;
|
|
1 | 2) [[ "$is_day" == "1" ]] && printf '⛅' || printf '☁' ;;
|
|
3) printf '☁' ;;
|
|
45 | 48) printf '🌫' ;;
|
|
51 | 53 | 55 | 56 | 57) printf '🌦' ;;
|
|
61 | 63 | 65 | 66 | 67 | 80 | 81 | 82) printf '🌧' ;;
|
|
71 | 73 | 75 | 77 | 85 | 86) printf '🌨' ;;
|
|
95 | 96 | 99) printf '⛈' ;;
|
|
*) printf '☁' ;;
|
|
esac
|
|
}
|
|
|
|
weather_description() {
|
|
case "$1" in
|
|
0) printf 'Clear sky' ;;
|
|
1) printf 'Mainly clear' ;;
|
|
2) printf 'Partly cloudy' ;;
|
|
3) printf 'Overcast' ;;
|
|
45 | 48) printf 'Fog' ;;
|
|
51) printf 'Light drizzle' ;;
|
|
53) printf 'Drizzle' ;;
|
|
55) printf 'Dense drizzle' ;;
|
|
56 | 57) printf 'Freezing drizzle' ;;
|
|
61) printf 'Slight rain' ;;
|
|
63) printf 'Rain' ;;
|
|
65) printf 'Heavy rain' ;;
|
|
66 | 67) printf 'Freezing rain' ;;
|
|
71) printf 'Slight snow' ;;
|
|
73) printf 'Snow' ;;
|
|
75) printf 'Heavy snow' ;;
|
|
77) printf 'Snow grains' ;;
|
|
80) printf 'Rain showers' ;;
|
|
81) printf 'Rain showers' ;;
|
|
82) printf 'Heavy rain showers' ;;
|
|
85 | 86) printf 'Snow showers' ;;
|
|
95) printf 'Thunderstorm' ;;
|
|
96 | 99) printf 'Thunderstorm with hail' ;;
|
|
*) printf 'Weather unavailable' ;;
|
|
esac
|
|
}
|
|
|
|
load_geocode() {
|
|
if [[ -f "$geo_cache_file" ]]; then
|
|
cat "$geo_cache_file"
|
|
return
|
|
fi
|
|
|
|
local encoded_query response
|
|
encoded_query="$(url_encode "$location_query")"
|
|
response="$(
|
|
curl \
|
|
--silent \
|
|
--show-error \
|
|
--fail \
|
|
--max-time 10 \
|
|
"https://geocoding-api.open-meteo.com/v1/search?name=${encoded_query}&count=1&language=en&format=json" 2>/dev/null || true
|
|
)"
|
|
|
|
if jq -e '.results[0] | .name and .latitude and .longitude and .timezone' >/dev/null <<<"$response"; then
|
|
jq -c '.results[0] | {name, admin1, country, latitude, longitude, timezone}' <<<"$response" | tee "$geo_cache_file"
|
|
return
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
fetch_weather() {
|
|
local latitude="$1"
|
|
local longitude="$2"
|
|
local timezone="$3"
|
|
|
|
curl \
|
|
--silent \
|
|
--show-error \
|
|
--fail \
|
|
--max-time 10 \
|
|
"https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,relative_humidity_2m,apparent_temperature,weather_code,wind_speed_10m,is_day&timezone=$(url_encode "$timezone")" 2>/dev/null || true
|
|
}
|
|
|
|
format_weather() {
|
|
local place_json="$1"
|
|
local weather_json="$2"
|
|
local name region place code is_day icon description temperature feels_like humidity wind text tooltip
|
|
|
|
name="$(jq -r '.name' <<<"$place_json")"
|
|
region="$(jq -r '.admin1 // empty' <<<"$place_json")"
|
|
place="$name"
|
|
if [[ -n "$region" ]]; then
|
|
place+=", $region"
|
|
fi
|
|
|
|
code="$(jq -r '.current.weather_code' <<<"$weather_json")"
|
|
is_day="$(jq -r '.current.is_day' <<<"$weather_json")"
|
|
icon="$(weather_icon "$code" "$is_day")"
|
|
description="$(weather_description "$code")"
|
|
temperature="$(jq -r '.current.temperature_2m | round | "\(.)"' <<<"$weather_json")"
|
|
feels_like="$(jq -r '.current.apparent_temperature | round | "\(.)"' <<<"$weather_json")"
|
|
humidity="$(jq -r '.current.relative_humidity_2m | round | "\(.)"' <<<"$weather_json")"
|
|
wind="$(jq -r '.current.wind_speed_10m | round | "\(.)"' <<<"$weather_json")"
|
|
|
|
text="${icon} ${temperature}°C"
|
|
tooltip="${place}: ${description}. Feels like ${feels_like}°C, humidity ${humidity}%, wind ${wind} km/h"
|
|
|
|
emit_json "$text" "$tooltip"
|
|
}
|
|
|
|
mkdir -p "$cache_dir"
|
|
|
|
if ! place_json="$(load_geocode)"; then
|
|
emit_cached_or_error
|
|
exit 0
|
|
fi
|
|
|
|
latitude="$(jq -r '.latitude' <<<"$place_json")"
|
|
longitude="$(jq -r '.longitude' <<<"$place_json")"
|
|
timezone="$(jq -r '.timezone' <<<"$place_json")"
|
|
|
|
weather_json="$(fetch_weather "$latitude" "$longitude" "$timezone")"
|
|
|
|
if jq -e '.current | .temperature_2m and .relative_humidity_2m and .apparent_temperature and .weather_code and .wind_speed_10m and .is_day' >/dev/null <<<"$weather_json"; then
|
|
format_weather "$place_json" "$weather_json" | tee "$weather_cache_file"
|
|
exit 0
|
|
fi
|
|
|
|
emit_cached_or_error
|