summaryrefslogtreecommitdiff
path: root/ar/.local/bin/statusbar
diff options
context:
space:
mode:
Diffstat (limited to 'ar/.local/bin/statusbar')
-rwxr-xr-xar/.local/bin/statusbar/sb-battery68
-rwxr-xr-xar/.local/bin/statusbar/sb-bghitness19
-rwxr-xr-xar/.local/bin/statusbar/sb-brightness11
-rwxr-xr-xar/.local/bin/statusbar/sb-clock77
-rwxr-xr-xar/.local/bin/statusbar/sb-cpu12
-rwxr-xr-xar/.local/bin/statusbar/sb-cpubars44
-rwxr-xr-xar/.local/bin/statusbar/sb-disk27
-rwxr-xr-xar/.local/bin/statusbar/sb-ecrypt12
-rwxr-xr-xar/.local/bin/statusbar/sb-forecast402
-rwxr-xr-xar/.local/bin/statusbar/sb-help-icon22
-rwxr-xr-xar/.local/bin/statusbar/sb-internet42
-rwxr-xr-xar/.local/bin/statusbar/sb-iplocate15
-rwxr-xr-xar/.local/bin/statusbar/sb-keyboard35
-rwxr-xr-xar/.local/bin/statusbar/sb-mailbox23
-rwxr-xr-xar/.local/bin/statusbar/sb-memory18
-rwxr-xr-xar/.local/bin/statusbar/sb-mpdup8
-rwxr-xr-xar/.local/bin/statusbar/sb-music78
-rwxr-xr-xar/.local/bin/statusbar/sb-nettraf29
-rwxr-xr-xar/.local/bin/statusbar/sb-news17
-rwxr-xr-xar/.local/bin/statusbar/sb-packages37
-rwxr-xr-xar/.local/bin/statusbar/sb-popupgrade9
-rwxr-xr-xar/.local/bin/statusbar/sb-price67
-rwxr-xr-xar/.local/bin/statusbar/sb-queues40
-rwxr-xr-xar/.local/bin/statusbar/sb-repos130
-rwxr-xr-xar/.local/bin/statusbar/sb-tasks84
-rwxr-xr-xar/.local/bin/statusbar/sb-torrent33
-rwxr-xr-xar/.local/bin/statusbar/sb-volume43
27 files changed, 1402 insertions, 0 deletions
diff --git a/ar/.local/bin/statusbar/sb-battery b/ar/.local/bin/statusbar/sb-battery
new file mode 100755
index 0000000..faf3d04
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-battery
@@ -0,0 +1,68 @@
+#!/bin/sh
+
+# Prints all batteries, their percentage remaining and an emoji corresponding
+# to charge status (πŸ”Œ for plugged up, πŸ”‹ for discharging on battery, etc.).
+
+# Function to get the battery status icon
+get_status_icon() {
+ case "$1" in
+ Full) echo "⚑" ;;
+ Discharging) echo "πŸ”‹" ;;
+ Charging) echo "πŸ”Œ" ;;
+ "Not charging") echo "πŸ›‘" ;;
+ Unknown) echo "♻️" ;;
+ *) echo "" ;;
+ esac
+}
+
+# Function to print battery status
+battery_status() {
+ device=$1
+ capacity=$(cat "$device/capacity" 2>/dev/null)
+ status=$(cat "$device/status" 2>/dev/null)
+ icon=$(get_status_icon "$status")
+ [ -z "$icon" ] && return
+ case $(basename "$device") in
+ BAT?*)
+ [ "$icon" = "πŸ”‹" ] && [ "$capacity" -le 25 ] && warn="❗"
+ printf "%s%s%d%%" "$icon" "$warn" "$capacity"
+ ;;
+ hid*)
+ model="$(cat "$device/model_name")"
+ notify-send "$icon $model:" "$capacity%"
+ ;;
+ esac
+ unset warn
+}
+
+devices() {
+ for battery in /sys/class/power_supply/$1; do
+ battery_status "$battery"
+ done && printf "\\n"
+}
+
+bluetooth() {
+ bluedevices=$(upower -e | grep -iv 'line' | grep -iv 'display' | grep -v 'BAT[0-9]' | grep -v 'hid')
+ for bluedevice in $bluedevices; do
+ bluedevice_name=$(upower -i "$bluedevice" | grep "model" | awk -F ': ' '{print $2}' | sed 's/ //g')
+ bluedevice_battery=$(upower -i "$bluedevice" | grep "percentage" | awk -F ': ' '{print $2}' | sed 's/ //g')
+ if [ -n "$bluedevice_battery" ]; then
+ notify-send "πŸ”‹ $bluedevice_name:" "$bluedevice_battery"
+ fi
+ done
+}
+
+# Handle mouse click actions
+case "$BLOCK_BUTTON" in
+2) bluetooth && devices "hid*" ;; # Middle click for Bluetooth battery levels
+3) notify-send "πŸ”‹ Battery module" "\- πŸ”‹: discharging
+- πŸ›‘: not charging
+- ♻️: stagnant charge
+- πŸ”Œ: charging
+- ⚑: fully charged
+- ❗: battery very low!
+- Middle click: bluetooth battery levels via upower" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+devices "BAT?*"
diff --git a/ar/.local/bin/statusbar/sb-bghitness b/ar/.local/bin/statusbar/sb-bghitness
new file mode 100755
index 0000000..0aabfb6
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-bghitness
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+# current brightness
+curr_brightness=$(cat /sys/class/backlight/*/brightness)
+
+# max_brightness
+max_brightness=$(cat /sys/class/backlight/*/max_brightness)
+
+# brightness percentage
+brightness_per=$((100 * curr_brightness / max_brightness))
+
+case $BLOCK_BUTTON in
+3) notify-send "πŸ’‘ Brightness module" "\- Shows current brightness level β˜€οΈ." ;;
+4) pkexec brillo -A 5 -q ;;
+5) pkexec brillo -U 5 -q ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+echo "πŸ’‘${brightness_per}%"
diff --git a/ar/.local/bin/statusbar/sb-brightness b/ar/.local/bin/statusbar/sb-brightness
new file mode 100755
index 0000000..909e676
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-brightness
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+3) notify-send "πŸ”† Backlight module
+- Scroll up & down changes backlight" ;;
+4) monbright -inc 5 ;;
+5) monbright -dec 5 ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+monitorbright
diff --git a/ar/.local/bin/statusbar/sb-clock b/ar/.local/bin/statusbar/sb-clock
new file mode 100755
index 0000000..e0e8c53
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-clock
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# Get current hour and minute
+hour=$(date '+%I')
+minute=$(date '+%M')
+calendar="πŸ—“οΈ"
+
+# Determine the icon based on hour and minute
+if crontab -l 2>/dev/null | grep -q '^[^#[:space:]]'; then
+ if [ "$minute" -ge 30 ]; then
+ case "$hour" in
+ "00" | "12") icon="πŸ•§" ;; # 12:30
+ "01" | "13") icon="πŸ•œ" ;; # 1:30
+ "02" | "14") icon="πŸ•" ;; # 2:30
+ "03" | "15") icon="πŸ•ž" ;; # 3:30
+ "04" | "16") icon="πŸ•Ÿ" ;; # 4:30
+ "05" | "17") icon="πŸ• " ;; # 5:30
+ "06" | "18") icon="πŸ•‘" ;; # 6:30
+ "07" | "19") icon="πŸ•’" ;; # 7:30
+ "08" | "20") icon="πŸ•£" ;; # 8:30
+ "09" | "21") icon="πŸ•€" ;; # 9:30
+ "10" | "22") icon="πŸ•₯" ;; # 10:30
+ "11" | "23") icon="πŸ•¦" ;; # 11:30
+ esac
+ else
+ case "$hour" in
+ "00" | "12") icon="πŸ•›" ;; # 12:00
+ "01" | "13") icon="πŸ•" ;; # 1:00
+ "02" | "14") icon="πŸ•‘" ;; # 2:00
+ "03" | "15") icon="πŸ•’" ;; # 3:00
+ "04" | "16") icon="πŸ•“" ;; # 4:00
+ "05" | "17") icon="πŸ•”" ;; # 5:00
+ "06" | "18") icon="πŸ••" ;; # 6:00
+ "07" | "19") icon="πŸ•–" ;; # 7:00
+ "08" | "20") icon="πŸ•—" ;; # 8:00
+ "09" | "21") icon="πŸ•˜" ;; # 9:00
+ "10" | "22") icon="πŸ•™" ;; # 10:00
+ "11" | "23") icon="πŸ•š" ;; # 11:00
+ esac
+ fi
+else
+ icon="⏰"
+fi
+
+# Shows the current moon phase.
+moonfile="${XDG_DATA_HOME:-${HOME}/.local/share}/moonphase"
+
+[ -s "$moonfile" ] && [ "$(stat -c %y "$moonfile" 2>/dev/null | cut -d' ' -f1)" = "$(date '+%Y-%m-%d')" ] ||
+ { curl -sf "wttr.in/?format=%m" >"$moonfile" || exit 1; }
+
+moon="$(cat "$moonfile")"
+
+case $BLOCK_BUTTON in
+1)
+ notify-send "This Month" "$(cal | sed "s/\<$(date +'%B' | tr -d ' ')\>/<b><span color='blue'>&<\/span><\/b>/;s/\<$(date +'%Y' | sed 's/ //g')\>/<b><span color='blue'>&<\/span><\/b>/;s/\<$(date +'%B' | sed 's/ //g')\>/<b><span color='blue'>&<\/span><\/b>/;s/\<$(date +'%e' | sed 's/ //g')\>/<b><span color='red'>&<\/span><\/b>/")" && notify-send "Appointments" "$(calcurse -d3)"
+ ;;
+2) setsid -f "$TERMINAL" -e calcurse ;;
+3)
+ notify-send "πŸ“… Time/date module" "\- Left click to show upcoming appointments for the next three days via \`calcurse -d3\` and show the month via \`cal\`
+- Left click also displays the current time in other cities.
+- Middle click opens calcurse if installed"
+ notify-send "🌜 Moon phase module" "Displays current moon phase
+- πŸŒ‘: New
+- πŸŒ’: Waxing Crescent
+- πŸŒ“: First Quarter
+- πŸŒ”: Waxing Gibbous
+- πŸŒ•: Full
+- πŸŒ–: Waning Gibbous
+- πŸŒ—: Last Quarter
+- 🌘: Waning Crescent"
+ ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+7) timezones ;;
+esac
+
+# Output the formatted date and time
+date "+${moon-$calendar}%a,%d $icon%H:%M"
diff --git a/ar/.local/bin/statusbar/sb-cpu b/ar/.local/bin/statusbar/sb-cpu
new file mode 100755
index 0000000..9dfbb54
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-cpu
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+1) notify-send "πŸ–₯ CPU hogs" "$(ps axch -o cmd:15,%cpu --sort=-%cpu | head)\\n(100% per core)" ;;
+2) setsid -f "$TERMINAL" -e htop ;;
+3) notify-send "πŸ–₯ CPU module " "\- Shows CPU temperature
+- Left click to show intensive processes
+- Middle click to open htop" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+sensors | awk '/Core 0/ {printf "πŸ‰%dΒ°\n", $3}'
diff --git a/ar/.local/bin/statusbar/sb-cpubars b/ar/.local/bin/statusbar/sb-cpubars
new file mode 100755
index 0000000..ce677ef
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-cpubars
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Module showing CPU load as a changing bars.
+# Just like in polybar.
+# Each bar represents amount of load on one core since
+# last run.
+
+# Cache in tmpfs to improve speed and reduce SSD load
+cache=/tmp/cpubarscache
+
+case $BLOCK_BUTTON in
+2) setsid -f "$TERMINAL" -e htop ;;
+3) notify-send "πŸͺ¨ CPU load module" "Each bar represents one CPU core" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# id total idle
+stats=$(awk '/cpu[0-9]+/ {printf "%d %d %d\n", substr($1,4), ($2 + $3 + $4 + $5), $5 }' /proc/stat)
+[ ! -f $cache ] && echo "$stats" >"$cache"
+old=$(cat "$cache")
+printf "πŸͺ¨"
+echo "$stats" | while read -r row; do
+ id=${row%% *}
+ rest=${row#* }
+ total=${rest%% *}
+ idle=${rest##* }
+
+ case "$(echo "$old" | awk '{if ($1 == id)
+ printf "%d\n", (1 - (idle - $3) / (total - $2))*100 /12.5}' \
+ id="$id" total="$total" idle="$idle")" in
+
+ "0") printf "▁" ;;
+ "1") printf "β–‚" ;;
+ "2") printf "β–ƒ" ;;
+ "3") printf "β–„" ;;
+ "4") printf "β–…" ;;
+ "5") printf "β–†" ;;
+ "6") printf "β–‡" ;;
+ "7") printf "β–ˆ" ;;
+ "8") printf "β–ˆ" ;;
+ esac
+done
+printf "\\n"
+echo "$stats" >"$cache"
diff --git a/ar/.local/bin/statusbar/sb-disk b/ar/.local/bin/statusbar/sb-disk
new file mode 100755
index 0000000..3c92f00
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-disk
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Status bar module for disk space
+# $1 should be drive mountpoint, otherwise assumed /.
+
+location=${1:-/}
+
+[ -d "$location" ] || exit
+
+case "$location" in
+"/home"*) icon="🏠" ;;
+"/mnt"*) icon="πŸ’Ύ" ;;
+*) icon="πŸ’»" ;;
+esac
+
+usage=$(df -h "$location" | awk ' /[0-9]/ {print $3 "/" $2}')
+
+case $BLOCK_BUTTON in
+1) notify-send "πŸ’½ Disk space" "$(df -h --output=target,used,size)" ;;
+2) notify-send "πŸ’½ Disk usage" "$icon: $usage" ;;
+3) notify-send "πŸ’½ Disk module" "\- Shows used hard drive space
+- Left click to show all disk info
+- Middle click to show disk usage" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+printf "%s%s\n" "$icon" "$(df -hP "$location" | awk ' /[0-9]/ {print $5}')"
diff --git a/ar/.local/bin/statusbar/sb-ecrypt b/ar/.local/bin/statusbar/sb-ecrypt
new file mode 100755
index 0000000..24c4cb3
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-ecrypt
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+is_mounted() { mount | grep -q "$HOME/Private"; }
+
+case $BLOCK_BUTTON in
+1) "${XDG_SCRIPTS_HOME:-${HOME}/.local/bin}/ecrypt" ;;
+3) notify-send "πŸ”’ Encrypted Media Folder " "\- Shows mount status of Media
+- Left click to toggle mount" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+is_mounted "$MOUNT_POINT" && echo "πŸ”‘" || echo "πŸ”’"
diff --git a/ar/.local/bin/statusbar/sb-forecast b/ar/.local/bin/statusbar/sb-forecast
new file mode 100755
index 0000000..9966c61
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-forecast
@@ -0,0 +1,402 @@
+#!/bin/sh
+
+# Displays today's snow chance (πŸ‚), precipication chance (β˜”), humidity (πŸ’§), wind speed (🎐), and current (feel like) temperature (🌞).
+# Usually intended for the statusbar.
+
+LOCATION=$(curl -s http://ip-api.com/json | jq -r '[.regionName, .countryCode] | join(",")')
+
+url="${WTTRURL:-wttr.in}"
+weatherreport="${XDG_CACHE_HOME:-${HOME}/.cache}/weatherreport"
+weatherreportjson="${XDG_CACHE_HOME:-${HOME}/.cache}/weatherreport.json"
+
+error() {
+ notify-send -u critical "β›” Failed to update 'weather$1'"
+ exit 1
+}
+
+# Get a weather report from 'wttr.in' and save it locally.
+getweatherreport() {
+ (timeout --signal=1 10s curl -sf "$url/$LOCATION" >"$weatherreport" &&
+ printf "\nUpdated: %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" >>"$weatherreport") ||
+ error "report"
+}
+
+getweatherreportjson() {
+ timeout --signal=1 10s curl -sf "$url/$LOCATION?format=j1" >"$weatherreportjson" || error "reportjson"
+}
+
+# Forecast should be updated every 3 hours, but set 3600 to check for reliability.
+checkforecast() {
+ [ -s "$1" ] && [ "$(($(date +%s) - $(stat -c %Y "$1")))" -le 3600 ]
+}
+
+get_current_hour() { date +%H | sed 's/^0*//'; }
+
+get_nearest_hourly() {
+ current_hour=$(get_current_hour)
+ hour_index=$((current_hour / 3))
+ jq ".weather[0].hourly[$hour_index]" "$weatherreportjson"
+}
+
+getprecip() { get_nearest_hourly | jq -r '.chanceofrain'; }
+
+gethighprecip() { jq -r '.weather[0].hourly[].chanceofrain' "$weatherreportjson" | sort -rn | head -1; }
+
+getsnow() { get_nearest_hourly | jq -r '.chanceofsnow'; }
+
+getwind() { get_nearest_hourly | jq -r '.windspeedKmph'; }
+
+gettemp() { get_nearest_hourly | jq -r '.tempC'; }
+
+getfeelslike() { get_nearest_hourly | jq -r '.FeelsLikeC'; }
+
+getlowtemp() { jq -r '.weather[0].hourly[].tempC' "$weatherreportjson" | sort -n | head -1; }
+
+gethightemp() { jq -r '.weather[0].hourly[].tempC' "$weatherreportjson" | sort -rn | head -1; }
+
+gethumidity() {
+ humidity=$(get_nearest_hourly | jq -r '.humidity')
+ case "$humidity" in
+ [0-9] | [1-2][0-9]) echo "🏜️: $humidity%" ;;
+ [3-4][0-9]) echo "🌲: $humidity%" ;;
+ [5-6][0-9]) echo "πŸ’§: $humidity%" ;;
+ [7-8][0-9]) echo "πŸ’¦: $humidity%" ;;
+ 9[0-9] | 100) echo "🌊: $humidity%" ;;
+ esac
+}
+
+getdesc() { get_nearest_hourly | jq -r '.weatherDesc[0].value' | sed 's/ $//'; }
+
+showweather() {
+ case "$(gettemp)" in
+ -[0-9]* | 0) icon="πŸ₯Ά" ;; # Temperature <= 0
+ [1-9] | [1-2][0-9]) icon="🌞" ;; # Temperature 1–29
+ 3* | [4-9]*) icon="πŸ₯΅" ;; # Temperature >= 30
+ esac
+ [ -n "$(gettemp)" ] && echo "$icon$(gettemp)Β°"
+}
+
+todayweather() {
+ printf "🌈 Today's weather: %s\nπŸ‚: %s%%\nβ˜”: %s(%s)mβ§Έs\n%s\n🎐: %sm/s\n🌞: %sΒ°(%sΒ°)\nπŸ₯Ά: %sΒ°\nπŸ₯΅: %sΒ°\n" \
+ "$(getdesc)" "$(getsnow)" "$(getprecip)" "$(gethighprecip)" "$(gethumidity)" "$(getwind)" "$(gettemp)" "$(getfeelslike)" "$(getlowtemp)" "$(gethightemp)"
+}
+
+# Show a Doppler RADAR of a user's preferred location.
+
+secs=600 # Download a new doppler radar if one hasn't been downloaded in $secs seconds.
+radarloc="${XDG_CACHE_HOME:-${HOME}/.cache}/radar"
+doppler="${XDG_CACHE_HOME:-${HOME}/.cache}/doppler.gif"
+
+pickloc() {
+ chosen="$(echo "US: CONUS: Continental United States
+US: Northeast
+US: Southeast
+US: PacNorthWest
+US: PacSouthWest
+US: UpperMissVly
+US: SouthMissVly
+US: SouthPlains
+US: NorthRockies
+US: SouthRockies
+US: Alaska
+US: Carib
+US: Hawaii
+US: CentGrLakes
+US: Conus-Large
+US: KABR: Aberdeen, SD
+US: KBIS: Bismarck, ND
+US: KFTG: Denver/Boulder, CO
+US: KDMX: Des Moines, IA
+US: KDTX: Detroit, MI
+US: KDDC: Dodge City, KS
+US: KDLH: Duluth, MN
+US: KCYS: Cheyenne, WY
+US: KLOT: Chicago, IL
+US: KGLD: Goodland, KS
+US: KUEX: Hastings, NE
+US: KGJX: Grand Junction, CO
+US: KGRR: Grand Rapids, MI
+US: KMVX: Fargo/Grand Forks, ND
+US: KGRB: Green Bay, WI
+US: KIND: Indianapolis, IN
+US: KJKL: Jackson, KY
+US: KARX: La Crosse, WI
+US: KILX: Lincoln/Central Illinois, IL
+US: KLVX: Louisville, KY
+US: KMQT: Marquette
+US: KMKX: Milwaukee, WI
+US: KMPX: Minneapolis, MN
+US: KAPX: Gaylord/Alpena, MI
+US: KLNX: North Platte, NE
+US: KIWX: N. Webster/Northern, IN
+US: KOAX: Omaha, NE
+US: KPAH: Paducah, KY
+US: KEAX: Pleasant Hill, MO
+US: KPUX: Pueblo, CO
+US: KDVN: Quad Cities, IA
+US: KUDX: Rapid City, SD
+US: KRIW: Riverton, WY
+US: KSGF: Springfield, MO
+US: KLSX: St. LOUIS, MO
+US: KFSD: Sioux Falls, SD
+US: KTWX: Topeka, KS
+US: KICT: Wichita, KS
+US: KVWX: Paducah, KY
+US: ICAO: Responsible Wfo
+US: KLTX: WILMINGTON, NC
+US: KCCX: State College/Central, PA
+US: KLWX: Sterling, VA
+US: KFCX: Blacksburg/Roanoke, VA
+US: KRAX: Raleigh/Durham, NC
+US: KGYX: Portland, ME
+US: KDIX: Mt Holly/Philadelphia, PA
+US: KPBZ: Pittsburgh, PA
+US: KAKQ: Wakefield, VA
+US: KMHX: Morehead City, NC
+US: KGSP: Greer/Greenville/Sprtbg, SC
+US: KILN: Wilmington/Cincinnati, OH
+US: KCLE: Cleveland, OH
+US: KCAE: Columbia, SC
+US: KBGM: Binghamton, NY
+US: KENX: Albany, NY
+US: KBUF: Buffalo, NY
+US: KCXX: Burlington, VT
+US: KCBW: Caribou, ME
+US: KBOX: Boston /Taunton, MA
+US: KOKX: New York City, NY
+US: KCLX: Charleston, SC
+US: KRLX: Charleston, WV
+US: ICAO: Responsible WFO
+US: KBRO: Brownsville, TX
+US: KABX: Albuquerque, NM
+US: KAMA: Amarillo, TX
+US: KFFC: Peachtree City/Atlanta, GA
+US: KEWX: Austin/Sanantonio, TX
+US: KBMX: Birmingham, AL
+US: KCRP: Corpus Christi, TX
+US: KFWS: Dallas / Ft. Worth, TX
+US: KEPZ: El Paso, TX
+US: KHGX: Houston/ Galveston, TX
+US: KJAX: Jacksonville, FL
+US: KBYX: Key West, FL
+US: KMRX: Morristown/knoxville, TN
+US: KLBB: Lubbock, TX
+US: KLZK: Little Rock, AR
+US: KLCH: Lake Charles, LA
+US: KOHX: Nashville, TN
+US: KMLB: Melbourne, FL
+US: KNQA: Memphis, TN
+US: KAMX: Miami, FL
+US: KMAF: Midland/odessa, TX
+US: KTLX: Norman, OK
+US: KHTX: Huntsville, AL
+US: KMOB: Mobile, AL
+US: KTLH: Tallahassee, FL
+US: KTBW: Tampa Bay Area, FL
+US: KSJT: San Angelo, TX
+US: KINX: Tulsa, OK
+US: KSRX: Tulsa, OK
+US: KLIX: New Orleans/slidell, LA
+US: KDGX: Jackson, MS
+US: KSHV: Shreveport, LA
+US: ICAO: Responsible WFO
+US: KLGX: Seattle / Tacoma, WA
+US: KOTX: Spokane, WA
+US: KEMX: Tucson, AZ
+US: KYUX: Phoenix, AZ
+US: KNKX: San Diego, CA
+US: KMUX: Monterey/san Francisco, CA
+US: KHNX: San Joaquin/hanford, CA
+US: KSOX: San Diego, CA
+US: KATX: Seattle / Tacoma, WA
+US: KIWA: Phoenix, AZ
+US: KRTX: Portland, OR
+US: KSFX: Pocatello, ID
+US: KRGX: Reno, NV
+US: KDAX: Sacramento, CA
+US: KMTX: Salt Lake City, UT
+US: KPDT: Pendleton, OR
+US: KMSX: Missoula, MT
+US: KESX: Las Vegas, NV
+US: KVTX: Los Angeles, CA
+US: KMAX: Medford, OR
+US: KFSX: Flagstaff, AZ
+US: KGGW: Glasgow, MT
+US: KLRX: Elko, NV
+US: KBHX: Eureka, CA
+US: KTFX: Great Falls, MT
+US: KCBX: Boise, ID
+US: KBLX: Billings, MT
+US: KICX: Salt Lake City, UT
+US: ICAO: Responsible Wfo W/ MSCF
+US: PABC: Anchorage, AK
+US: PAPD: Fairbanks, AK
+US: PHKM: Honolulu, HI
+US: PAHG: Anchorage, AK
+US: PAKC: Anchorage, AK
+US: PAIH: Anchorage, AK
+US: PHMO: Honolulu, HI
+US: PAEC: Fairbanks, AK
+US: TJUA: San Juan, PR
+US: PACG: Juneau, AK
+US: PHKI: Honolulu, HI
+US: PHWA: Honolulu, HI
+US: ICAO: Responsible Wfo W/ MSCF
+US: KFDR: Norman, OK
+US: PGUA: Guam
+US: KBBX: Sacramento, CA
+US: KFDX: Albuquerque, NM
+US: KGWX: Jackson, MS
+US: KDOX: Wakefield, VA
+US: KDYX: San Angelo, TX
+US: KEYX: Las Vegas, NV
+US: KEVX: Mobile, AL
+US: KHPX: Paducah, KY
+US: KTYX: Burlington, VT
+US: KGRK: Dallas / Ft. Worth, TX
+US: KPOE: Lake Charles, LA
+US: KEOX: Tallahassee, FL
+US: KHDX: El Paso, TX
+US: KDFX: San Antonio, TX
+US: KMXX: Birmingham, AL
+US: KMBX: Bismarck, ND
+US: KVAX: Jacksonville, FL
+US: KJGX: Peachtree City/atlanta, GA
+US: KVNX: Norman, OK
+US: KVBX: Vandenberg Afb: Orcutt, CA
+EU: Europe
+EU: GB: Great Brittain
+EU: SCAN: Scandinavia. Norway, Sweden And Denmark
+EU: ALPS: The Alps
+EU: NL: The Netherlands
+EU: DE: Germany
+EU: SP: Spain
+EU: FR: France
+EU: IT: Italy
+EU: PL: Poland
+EU: GR: Greece
+EU: TU: Turkey
+EU: RU: Russia
+EU: BA: Bahrain
+EU: BC: Botswana
+EU: SE: Republic of Seychelles
+EU: HU: Hungary
+EU: UK: Ukraine
+AF: AF: Africa
+AF: WA: West Africa
+AF: ZA: South Africa
+AF: DZ: Algeria
+AF: CE: Canary Islands
+AF: NG: Nigeria
+AF: TD: Chad
+AF: CG: Democratic Republic of Congo
+AF: EG: Egypt
+AF: ET: Ethiopia
+AF: CM: Cameroon
+AF: IS: Israel
+AF: LY: Libya
+AF: MG: Madagascar
+AF: MO: Morocco
+AF: BW: Namibia
+AF: SA: Saudi Arabia
+AF: SO: Somalia
+AF: SD: Sudan
+AF: TZ: Tanzania
+AF: TN: Tunisia
+AF: ZM: Zambia
+AF: KE: Kenya
+AF: AO: Angola
+DE: BAW: Baden-WΓΌrttemberg
+DE: BAY: Bavaria
+DE: BBB: Berlin
+DE: BBB: Brandenburg
+DE: HES: Hesse
+DE: MVP: Mecklenburg-Western Pomerania
+DE: NIB: Lower Saxony
+DE: NIB: Bremen
+DE: NRW: North Rhine-Westphalia
+DE: RPS: Rhineland-Palatinate
+DE: RPS: Saarland
+DE: SAC: Saxony
+DE: SAA: Saxony-Anhalt
+DE: SHH: Schleswig-Holstein
+DE: SHH: Hamburg
+DE: THU: Thuringia" | dmenu -r -i -l 50 -p "Select a radar to use as default:" | tr "[:lower:]" "[:upper:]")"
+
+ # Ensure user did not escape.
+ [ -z "$chosen" ] && exit 1
+
+ # Set continent code and radar code.
+ continentcode=${chosen%%:*}
+ radarcode=${chosen#* } radarcode=${radarcode%:*}
+
+ # Print codes to $radarloc file.
+ printf "%s,%s\\n" "$continentcode" "$radarcode" >"$radarloc"
+}
+
+getdoppler() {
+ cont=$(cut -c -2 "$radarloc")
+ loc=$(cut -c 4- "$radarloc")
+ notify-send "🌦️ Doppler RADAR" "Pulling most recent Doppler RADAR for $loc."
+ case "$cont" in
+ "US") curl -sL "https://radar.weather.gov/ridge/standard/${loc}_loop.gif" >"$doppler" ;;
+ "EU") curl -sL "https://api.sat24.com/animated/${loc}/rainTMC/2/" >"$doppler" ;;
+ "AF") curl -sL "https://api.sat24.com/animated/${loc}/rain/2/" >"$doppler" ;;
+ "DE")
+ loc="$(echo "$loc" | tr "[:upper:]" "[:lower:]")"
+ curl -sL "https://www.dwd.de/DWD/wetter/radar/radfilm_${loc}_akt.gif" >"$doppler"
+ ;;
+ esac
+}
+
+showdoppler() { setsid -f mpv --no-osc --loop=inf --no-terminal "$doppler"; }
+
+case $BLOCK_BUTTON in
+1)
+ [ "$MANPAGER" = "less -s" ] && pager=true || pager=false
+ [ "$pager" = "false" ] && {
+ export MANPAGER='less -s'
+ export LESS="R"
+ export LESS_TERMCAP_mb="$(printf '%b' '')"
+ export LESS_TERMCAP_md="$(printf '%b' '')"
+ export LESS_TERMCAP_me="$(printf '%b' '')"
+ export LESS_TERMCAP_so="$(printf '%b' '')"
+ export LESS_TERMCAP_se="$(printf '%b' '')"
+ export LESS_TERMCAP_us="$(printf '%b' '')"
+ export LESS_TERMCAP_ue="$(printf '%b' '')"
+ export LESSOPEN="| /usr/bin/highlight -O ansi %s 2>/dev/null"
+ }
+ setsid -f "$TERMINAL" -e less -Sf "${XDG_CACHE_HOME:-${HOME}/.cache}/weatherreport"
+ [ "$pager" = "false" ] && {
+ export MANPAGER="sh -c 'col -bx | bat -l man -p'"
+ export MANROFFOPT="-c"
+ }
+ ;;
+2)
+ [ ! -f "$radarloc" ] && pickloc && getdoppler
+ [ $(($(date '+%s') - $(stat -c %Y "$doppler"))) -gt "$secs" ] && getdoppler
+ showdoppler
+ ;;
+3)
+ notify-send "🌈 Weather module (updates every 3 hours)" "\- Left click for full forecast
+- Shift + left click to update forecast
+πŸ‚: Chance of snow (hidden if it's 0)
+β˜”: Chance of rain
+πŸ’§: Humidity (icon changes depending on the level)
+🎐: Wind speed
+🌞: Current (feel like) temperature
+πŸ₯Ά: Daily lowest temperature
+πŸ₯΅: Daily highest temperature"
+ notify-send "$(todayweather)"
+ notify-send "πŸ—ΊοΈ Doppler RADAR module" "\- Middle click for local Doppler RADAR
+- Shift + middle click to update RADAR location
+After $secs seconds, new clicks will also automatically update the doppler RADAR"
+ ;;
+6) getweatherreport && getweatherreportjson && notify-send "🌈 Updated forecast" ;;
+7) pickloc && getdoppler && showdoppler ;;
+8) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+checkforecast "$weatherreport" || { getweatherreport && pkill -RTMIN+15 "${STATUSBAR:-dwmblocks}" && sleep 3; }
+checkforecast "$weatherreportjson" || { getweatherreportjson && pkill -RTMIN+15 "${STATUSBAR:-dwmblocks}" && sleep 3; }
+showweather
diff --git a/ar/.local/bin/statusbar/sb-help-icon b/ar/.local/bin/statusbar/sb-help-icon
new file mode 100755
index 0000000..2717758
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-help-icon
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# The clickable help menu. Middle click to restart wm.
+
+# If dwm is running, use dwm's readme and restart.
+pidof dwm >/dev/null &&
+ READMEFILE=/usr/local/share/dwm/thesiah.mom
+restartwm() { pkill -HUP dwm; } ||
+ restartwm() { i3 restart; }
+
+case $BLOCK_BUTTON in
+1) groff -mom "${READMEFILE:-${XDG_DATA_HOME:-${HOME}/.local/share}/thesiah/thesiah.mom}" -Tpdf | zathura - ;;
+2) restartwm ;;
+3) notify-send "❓ Help module" "\- Left click to open THESIAH guide
+- Middle click to refresh window manager
+- Shift + Middle click to run system action
+- Shift + Right clict to lock screen" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+7) sysact ;;
+8) slock ;;
+esac
+echo "❓"
diff --git a/ar/.local/bin/statusbar/sb-internet b/ar/.local/bin/statusbar/sb-internet
new file mode 100755
index 0000000..3d4ff4e
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-internet
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+# Show wifi πŸ›œ and percent strength or πŸ“‘ if none.
+# Show 🌐 if connected to ethernet or ❎ if none.
+# Show πŸ›°οΈ if a vpn connection is active
+
+case $BLOCK_BUTTON in
+1)
+ "$TERMINAL" -e nmtui
+ pkill -RTMIN+7 dwmblocks
+ ;;
+3) notify-send "🌐 Internet module" "\- Left click to connect
+❌: wifi disabled
+πŸ“‘: no wifi connection
+πŸ›œ: wifi connection with quality
+❎: no ethernet
+🌐: ethernet working
+πŸ›°οΈ: vpn is active
+" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# Wifi
+if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ]; then
+ wifiicon="$(awk '/^\s*w/ { print "πŸ›œ" int($3 * 100 / 70) "%" }' /proc/net/wireless)"
+elif [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'down' ]; then
+ [ "$(cat /sys/class/net/w*/flags 2>/dev/null)" = '0x1003' ] && wifiicon="πŸ“‘" || wifiicon="❌"
+fi
+
+# Ethernet
+[ "$(cat /sys/class/net/e*/operstate 2>/dev/null)" = 'up' ] && ethericon="🌐" || ethericon="❎"
+
+# TUN
+[ -n "$(cat /sys/class/net/tun*/operstate 2>/dev/null)" ] && tunicon=" πŸ›°οΈ"
+
+if [ "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ] && [ ! "$(cat /sys/class/net/e*/operstate 2>/dev/null)" = 'up' ]; then
+ printf "%s%s\n" "$wifiicon" "$tunicon"
+elif [ ! "$(cat /sys/class/net/w*/operstate 2>/dev/null)" = 'up' ] && [ "$(cat /sys/class/net/e*/operstate 2>/dev/null)" = 'up' ]; then
+ printf "%s%s\n" "$ethericon" "$tunicon"
+else
+ printf "%s%s%s\n" "$wifiicon" " $ethericon" "$tunicon"
+fi
diff --git a/ar/.local/bin/statusbar/sb-iplocate b/ar/.local/bin/statusbar/sb-iplocate
new file mode 100755
index 0000000..d84445e
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-iplocate
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Gets your public ip address checks which country you are in and
+# displays that information in the statusbar
+#
+# https://www.maketecheasier.com/ip-address-geolocation-lookups-linux/
+
+set -e
+
+ifinstalled "geoip"
+addr="$(geoiplookup "$(curl -sfm 1 ifconfig.me 2>/dev/null)")"
+name="${addr##*, }"
+flag="$(grep "flag: $name" "${XDG_DATA_HOME:-${HOME}/.local/share}/larbs/emoji")"
+flag="${flag%% *}"
+printf "%s %s\\n" "$flag" "$name"
diff --git a/ar/.local/bin/statusbar/sb-keyboard b/ar/.local/bin/statusbar/sb-keyboard
new file mode 100755
index 0000000..6329020
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-keyboard
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+# works on any init system
+# requirements: dmenu, xorg-setxkbmap
+kb="$(setxkbmap -query | grep -oP 'layout:\s*\K\w+')" || exit 1
+
+case $BLOCK_BUTTON in
+1) fcitx5-remote -t && kill -44 "$(pidof "${STATUSBAR:-dwmblocks}")" ;;
+2)
+ kb_choice="$(awk '/! layout/{flag=1; next} /! variant/{flag=0} flag {print $2, "- " $1}' /usr/share/X11/xkb/rules/base.lst | dmenu -l 15)"
+ [ -z "$kb_choice" ] && exit 0
+ kb="$(echo "$kb_choice" | awk '{print $3}')"
+ setxkbmap "$kb"
+ pkill -RTMIN+10 "${STATUSBAR:-dwmblocks}"
+ ;;
+3) notify-send "⌨️ Input Method module" "\- Shows current input method (defalt US)
+- Left click to switch language (EN/KO)
+- Middle click to change keyboard" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+if [ "$kb" = "us" ] || [ "$kb" = "kr" ]; then
+ if [ "$(fcitx5-remote)" -eq 1 ]; then
+ echo "⌨️US"
+ elif [ "$(fcitx5-remote)" -eq 2 ]; then
+ case "$(fcitx5-remote -n)" in
+ *ko* | *Korean* | *hangul*) echo "⌨️KO" ;;
+ *) echo "⌨️$(setxkbmap -query | grep 'layout:' | sed 's/layout:\s*\(\S*\)/\1/g')" ;;
+ esac
+ else
+ echo "⌨️??"
+ fi
+else
+ echo "⌨️$kb"
+fi
diff --git a/ar/.local/bin/statusbar/sb-mailbox b/ar/.local/bin/statusbar/sb-mailbox
new file mode 100755
index 0000000..4496efc
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-mailbox
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# Displays number of unread mail and an loading icon if updating.
+# When clicked, brings up `neomutt`.
+
+case $BLOCK_BUTTON in
+1)
+ setsid -w -f "$TERMINAL" -e neomutt
+ pkill -RTMIN+20 "${STATUSBAR:-dwmblocks}"
+ ;;
+2) setsid -f mw -Y >/dev/null ;;
+3) notify-send "πŸ“¬ Mail module" "\- Shows unread mail
+- Shows πŸ”ƒ if syncing mail
+- Left click opens neomutt
+- Middle click syncs mail" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+unread="$(find "${XDG_DATA_HOME:-${HOME}/.local/share}"/mail/*/[Ii][Nn][Bb][Oo][Xx]/new/* -type f | wc -l 2>/dev/null)"
+
+pidof mbsync >/dev/null 2>&1 && icon="πŸ”ƒ"
+
+[ "$unread" = "0" ] && [ "$icon" = "" ] || echo "πŸ“¬$unread$icon"
diff --git a/ar/.local/bin/statusbar/sb-memory b/ar/.local/bin/statusbar/sb-memory
new file mode 100755
index 0000000..bc7085a
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-memory
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+case $BLOCK_BUTTON in
+1) notify-send "🐏 Memory hogs" "$(
+ ps axch -o cmd:15,%mem --sort=-%mem | head
+ echo
+ free --mebi | sed -n '2{p;q}' | awk '{printf ("πŸ‘Ÿ%2.2fGB/%2.2fGB\n", ( $3 / 1024), ($2 / 1024))}'
+)" ;;
+2) setsid -f "$TERMINAL" -e htop ;;
+3) notify-send "🐏 Memory module" "\- Shows Memory used/total
+- Left click to show memory hogs
+- Middle click to open htop" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+[ $(xrandr | grep "\*" | awk '{print $1}' | sed 's/x[0-9]*//g') -lt 1920 ] &&
+ free --mebi | sed -n '2{p;q}' | awk '{printf ("🐏%d%%\n", ($3/$2)*100+0.5 )}' ||
+ free --mebi | sed -n '2{p;q}' | awk '{printf ("🐏%dGB/%dGB", $3/1000+0.5,$2/1000+0.5)}'
diff --git a/ar/.local/bin/statusbar/sb-mpdup b/ar/.local/bin/statusbar/sb-mpdup
new file mode 100755
index 0000000..90e9c7e
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-mpdup
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+# This loop will update the mpd statusbar module whenever a command changes the
+# music player's status. mpd must be running on X's start for this to work.
+
+while :; do
+ mpc idle >/dev/null && kill -57 "$(pidof "${STATUSBAR:-dwmblocks}")" || break
+done
diff --git a/ar/.local/bin/statusbar/sb-music b/ar/.local/bin/statusbar/sb-music
new file mode 100755
index 0000000..e47fb06
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-music
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+truncate_string() {
+ local input="$1"
+ local max_length="$2"
+ if [ "${#input}" -gt "$max_length" ]; then
+ echo "${input:0:$((max_length - 2))}.."
+ else
+ echo "$input"
+ fi
+}
+
+filter() {
+ if ps -C mpd >/dev/null 2>&1; then
+ screen_width=$(xrandr | grep '\*' | awk '{print $1}' | cut -d'x' -f1)
+ artist=$(mpc current -f %artist%)
+ title=$(mpc current -f %title%)
+
+ if [ "$screen_width" -le 2048 ]; then
+ max_length=$((screen_width / 100))
+ artist=$(truncate_string "$artist" "$max_length")
+ title=$(truncate_string "$title" "$max_length")
+ else
+ artist="$(mpc current -f %artist%)"
+ title="$(mpc current -f %title%)"
+ fi
+
+ case "$(mpc status %state%)" in
+ "playing") prefix="🎡" ;;
+ "paused") prefix="⏸" ;;
+ *) return ;;
+ esac
+
+ indicators=""
+ [ "$(mpc status %single%)" = "on" ] && indicators="${indicators}πŸ”€"
+ [ "$(mpc status %random%)" = "on" ] && indicators="${indicators}πŸ”‚"
+ [ "$(mpc status %repeat%)" = "on" ] && indicators="${indicators}πŸ”"
+
+ sig=$(grep "${0##*/}" "${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwmblocks/config.h" | awk -F',' '{print $3}')
+ case $sig in
+ *0*)
+ echo "$prefix$artist - $title$([ -n "$indicators" ] && echo "$indicators")"
+ ;;
+ *1*)
+ echo "$prefix$artist - $title $(mpc status %currenttime%)/$(mpc status %totaltime%)$([ -n "$indicators" ] && echo "$indicators")"
+ ;;
+ esac
+ fi
+}
+
+[ "$(grep "${0##*/}" "${XDG_SOURCES_HOME:-${HOME}/.local/src}/suckless/dwmblocks/config.h" | awk -F',' '{print $3}')" -eq 0 ] && {
+ pidof -x sb-mpdup >/dev/null 2>&1 || sb-mpdup >/dev/null 2>&1 &
+}
+
+# Handling interaction based on button press
+case $BLOCK_BUTTON in
+1) # left click, opens ncmpcpp
+ mpc status | filter
+ setsid -f "$TERMINAL" -e ncmpcpp
+ ;;
+2) mpc toggle | filter ;; # middle click, pause/unpause
+3) # right click
+ notify-send "🎡 Music module" "\- Shows mpd song playing and status
+- 🎡 if playing
+- ⏸ if paused
+- πŸ”‚ if single on
+- πŸ” if repeat on
+- πŸ”€ if random on
+- Left click opens ncmpcpp
+- Middle click pauses/unpause
+- Scroll changes track"
+ notify-send "🎡 $(mpc current)" "⏭️ $(mpc queued)"
+ ;;
+4) mpc prev | filter ;; # scroll up, previous
+5) mpc next | filter ;; # scroll down, next
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+*) mpc status | filter ;; # default, show current status
+esac
diff --git a/ar/.local/bin/statusbar/sb-nettraf b/ar/.local/bin/statusbar/sb-nettraf
new file mode 100755
index 0000000..7bba320
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-nettraf
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+# Module showing network traffic. Shows how much data has been received (RX) or
+# transmitted (TX) since the previous time this script ran. So if run every
+# second, gives network traffic per second.
+
+case $BLOCK_BUTTON in
+1) setsid -f "$TERMINAL" -e bmon ;;
+3) notify-send "🌐 Network traffic module" "πŸ”»: Traffic received
+πŸ”Ί: Traffic transmitted" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+update() {
+ sum=0
+ for arg; do
+ read -r i <"$arg"
+ sum=$((sum + i))
+ done
+ cache=/tmp/${1##*/}
+ [ -f "$cache" ] && read -r old <"$cache" || old=0
+ printf %d\\n "$sum" >"$cache"
+ printf %d\\n $((sum - old))
+}
+
+rx=$(update /sys/class/net/[ew]*/statistics/rx_bytes)
+tx=$(update /sys/class/net/[ew]*/statistics/tx_bytes)
+
+printf "πŸ”»%4sB πŸ”Ί%4sB\\n" $(numfmt --to=iec $rx $tx)
diff --git a/ar/.local/bin/statusbar/sb-news b/ar/.local/bin/statusbar/sb-news
new file mode 100755
index 0000000..8bbbbf1
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-news
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Displays number of unread news items and an loading icon if updating.
+# When clicked, brings up `newsboat`.
+
+case $BLOCK_BUTTON in
+1) setsid "$TERMINAL" -e newsboat ;;
+2) setsid -f newsup >/dev/null && exit ;;
+3) notify-send "πŸ“° News module" "\- Shows unread news items
+- Shows πŸ”ƒ if updating with \`newsup\`
+- Left click opens newsboat
+- Middle click syncs RSS feeds
+<b>Note:</b> Only one instance of newsboat (including updates) may be running at a time" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+cat /tmp/newsupdate 2>/dev/null || echo "$(newsboat -x print-unread | awk '{ if($1>0) print "πŸ“°" $1}')$(cat "${XDG_CONFIG_HOME:-${HOME}/.config}"/newsboat/.update 2>/dev/null)"
diff --git a/ar/.local/bin/statusbar/sb-packages b/ar/.local/bin/statusbar/sb-packages
new file mode 100755
index 0000000..5955c75
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-packages
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# Displays number of upgradeable packages.
+# For this to work, have a `pacman -Sy` command run in the background as a
+# cronjob every so often as root. This script will then read those packages.
+# When clicked, it will run an upgrade via pacman.
+#
+# Add the following text as a file in /usr/share/libalpm/hooks/statusbar.hook:
+#
+# [Trigger]
+# Operation = Upgrade
+# Type = Package
+# Target = *
+#
+# [Action]
+# Description = Updating statusbar...
+# When = PostTransaction
+# Exec = /usr/bin/pkill -RTMIN+16 dwmblocks # Or i3blocks if using i3.
+
+case $BLOCK_BUTTON in
+1) setsid -f "$TERMINAL" -e sb-popupgrade && remaps ;;
+2) notify-send "$(/usr/bin/pacman -Qu)" "$(/usr/bin/yay -Qu --aur)" ;;
+3) notify-send "🎁 Upgrade module" "πŸ“¦: number of upgradable 'pacman' packages
+🧰: number of upgradable 'yay' packages
+- Left click to upgrade all packages
+- Middle click to show upgradable packages" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+pacnum=$(pacman -Qu | grep -Fcv "[ignored]" | sed "s/^/πŸ“¦/;s/^πŸ“¦0$//g")
+yaynum=$(yay -Qu --aur | grep -Fcv "[ignored]" | sed "s/^/🧰/;s/^🧰0$//g")
+upgradable=""
+[ -n "$pacnum" ] && upgradable="${upgradable}${pacnum} "
+[ -n "$yaynum" ] && upgradable="${upgradable}${yaynum} "
+upgradable=$(echo "$upgradable" | sed 's/ *$//')
+
+printf "%s\n" "$upgradable"
diff --git a/ar/.local/bin/statusbar/sb-popupgrade b/ar/.local/bin/statusbar/sb-popupgrade
new file mode 100755
index 0000000..14036eb
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-popupgrade
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+printf "Beginning upgrade\\n"
+
+yay -Syu
+pkill -RTMIN+16 "${STATUSBAR:-dwmblocks}"
+
+printf "\\nUpgrade complete.\\nPress <Enter> to exit window.\\n\\n"
+read -r _
diff --git a/ar/.local/bin/statusbar/sb-price b/ar/.local/bin/statusbar/sb-price
new file mode 100755
index 0000000..46731c2
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-price
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+# Usage:
+# price <currency-base currency> <name of currency> <icon> <signal>
+# price bat-btc "Basic Attention Token" 🦁 24
+# This will give the price of BAT denominated in BTC and will update on
+# signal 24.
+# When the name of the currency is multi-word, put it in quotes.
+
+[ -z "$1" ] && exit 1
+
+url="${CRYPTOURL:-rate.sx}"
+target="${1%%-*}"
+denom="${1##*-}"
+name="${2:-$1}"
+icon="${3:-πŸ’°}"
+case "$denom" in
+"$target" | usd)
+ denom="usd"
+ symb="$"
+ ;;
+gbp) symb="Β£" ;;
+eur) symb="€" ;;
+btc) symb="ο…š" ;;
+esac
+interval="@1d" # History contained in chart preceded by '@' (7d = 7 days)
+dir="${XDG_CACHE_HOME:-${HOME}/.cache}/crypto-prices"
+pricefile="$dir/$target-$denom"
+chartfile="$dir/$target-$denom-chart"
+filestat="$(stat -c %x "$pricefile" 2>/dev/null)"
+
+[ -d "$dir" ] || mkdir -p "$dir"
+
+updateprice() { curl -sf \
+ --fail-early "${denom}.${url}/1${target}" "${denom}.${url}/${target}${interval}" \
+ --output "$pricefile" --output "$chartfile" ||
+ rm -f "$pricefile" "$chartfile"; }
+
+[ "${filestat%% *}" != "$(date '+%Y-%m-%d')" ] &&
+ updateme="1"
+
+case $BLOCK_BUTTON in
+1) setsid "$TERMINAL" -e less -Srf "$chartfile" ;;
+2)
+ notify-send -u low "$icon Updating..." "Updating $name price..."
+ updateme="1"
+ showupdate="1"
+ ;;
+3)
+ uptime="$(date -d "$filestat" '+%D at %T' | sed "s|$(date '+%D')|Today|")"
+ notify-send "$icon $name module" "\- <b>Exact price: \$$(cat "$pricefile")</b>
+- Left click for chart of changes
+- Middle click to update
+- Shows πŸ”ƒ if updating prices
+- <b>Last updated:
+$uptime</b>"
+ ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+[ -n "$updateme" ] &&
+ updateprice "$target" &&
+ [ -n "$showupdate" ] &&
+ notify-send "$icon Update complete" "$name price is now
+\$$(cat "$pricefile")"
+
+[ -f "$pricefile" ] && printf "%s%s%0.2f" "$icon" "$symb" "$(cat "$pricefile")"
diff --git a/ar/.local/bin/statusbar/sb-queues b/ar/.local/bin/statusbar/sb-queues
new file mode 100755
index 0000000..7cd48a7
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-queues
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+notify_filenames() {
+ while IFS= read -r line; do
+ id=$(echo "$line" | awk '{print $1}')
+ url=$(tsp -l | awk -v id="$id" 'flag && /notify-send/ {print $0; flag=0} $1 == id {flag=1}' | grep -o 'https://[^\"]*')
+ if [ -n "$url" ]; then
+ decoded_url=$(echo "$url" | sed 's/&amp;/\&/g')
+ yt-dlp --no-playlist --simulate --get-filename "$decoded_url" 2>/dev/null | while IFS= read -r filename; do
+ notify-send "πŸ”½ Downloading:" "$filename"
+ done
+ else
+ notify-send "πŸͺΉ No URL extracted for task $id"
+ fi
+ done <<EOF
+$(tsp -l | awk '/running/ && /yt-dlp/')
+EOF
+ if [ -z "$url" ]; then
+ notify-send "πŸ’€ No active yt-dlp downloads"
+ fi
+ pkill -RTMIN+21 "${STATUSBAR:-dwmblocks}"
+}
+
+# This block displays the number of running and queued background tasks. Requires tsp.
+num=$(tsp -l | awk -v numr=0 -v numq=0 '{if (!/notify-send/ && /running/) numr++; if (!/notify-send/ && /queued/) numq++} END{print numr"|"numq}')
+
+# Handle mouse clicks
+case $BLOCK_BUTTON in
+1) setsid -f "$TERMINAL" -e sh -c 'tsp -l; echo "\nPress enter to close..." ; read REPLY' ;;
+2) setsid -f "$TERMINAL" -e sh -c 'tsp -t' ;;
+3)
+ notify_filenames
+ notify-send "πŸ“ Tasks module" "πŸ€–: number of running/queued background tasks
+- Left click to show all tasks
+- Middle click to show the current task progress"
+ ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+cat /tmp/qplaylist 2>/dev/null || ([ "$num" != "0|0" ] && echo "πŸ€–$num")
diff --git a/ar/.local/bin/statusbar/sb-repos b/ar/.local/bin/statusbar/sb-repos
new file mode 100755
index 0000000..1dad9f1
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-repos
@@ -0,0 +1,130 @@
+#!/bin/bash
+
+pidof transmission-daemon >/dev/null && exit 1
+
+# Directories containing Git repositories
+DOTFILES_REPOS="$HOME/.dotfiles"
+SUCKLESS_REPOS="$HOME/.local/src/suckless"
+PRIVATE_REPOS="$HOME/Private/repos"
+PUBLIC_REPOS="$HOME/Public/repos"
+
+# Icon indicators
+DOTFILES_ICON="βš™οΈ"
+SUCKLESS_ICON="πŸ› "
+PRIVATE_ICON="🏠"
+PUBLIC_ICON="🏒"
+
+# Function to parse Git status and format symbols
+get_git_status_symbols() {
+ git status --porcelain | awk '
+ {
+ if ($1 == "??") {
+ changes["?"]++
+ } else if ($1 ~ /^[MADR]$/) {
+ changes[$1]++
+ }
+ }
+ END {
+ for (change in changes) {
+ printf "%s%s", change, changes[change]
+ }
+ }'
+}
+
+# Function to check for unpushed commits
+get_unpushed_commits() { git cherry -v 2>/dev/null | wc -l; }
+
+# Function to check for unpulled commits
+get_unpulled_commits() { git rev-list --count HEAD..@{upstream} 2>/dev/null; }
+
+# Function to check Git repository status for multiple repos
+check_multi_repo_status() {
+ local dir="$1"
+ local icon="$2"
+ local status=""
+ local changed_repos=""
+
+ while IFS= read -r git_dir; do
+ local repo_dir="${git_dir%/.git}"
+ cd "$repo_dir" || continue
+
+ changes=$(get_git_status_symbols)
+ unpushed=$(get_unpushed_commits)
+ unpulled=$(get_unpulled_commits)
+
+ if [ -n "$changes" ] || [ "$unpushed" -gt 0 ] || [ "$unpulled" -gt 0 ]; then
+ status+="$icon$changes"
+ [ "$unpushed" -gt 0 ] && status+="↑$unpushed"
+ [ "$unpulled" -gt 0 ] && status+="↓$unpulled"
+ status+=" "
+ changed_repos+="$repo_dir"
+ fi
+ done < <(find "$dir" -mindepth 2 -maxdepth 2 -type d -name ".git" 2>/dev/null)
+
+ printf "%s%s" "$status" "$changed_repos"
+}
+
+# Function to check Git repository status for a single repository
+check_single_repo_status() {
+ local dir="$1"
+ local icon="$2"
+ local repo_status=""
+ local changed_repo=""
+
+ if [ -d "$dir/.git" ]; then
+ cd "$dir" || return
+
+ changes=$(get_git_status_symbols)
+ unpushed=$(get_unpushed_commits)
+ unpulled=$(get_unpulled_commits)
+
+ if [ -n "$changes" ] || [ "$unpushed" -gt 0 ] || [ "$unpulled" -gt 0 ]; then
+ repo_status+="$icon$changes"
+ [ "$unpushed" -gt 0 ] && repo_status+="↑$unpushed"
+ [ "$unpulled" -gt 0 ] && repo_status+="↓$unpulled"
+ repo_status+=" "
+ changed_repo="$dir"
+ fi
+ fi
+
+ printf "%s%s" "$repo_status" "$changed_repo"
+}
+
+# Check statuses for repositories
+dotfiles_status=$(check_single_repo_status "$DOTFILES_REPOS" "$DOTFILES_ICON" | awk -F' ' '{print $1}')
+dotfiles_changes=$(check_single_repo_status "$DOTFILES_REPOS" "$DOTFILES_ICON" | awk -F' ' '{print $2}')
+
+suckless_status=$(check_single_repo_status "$SUCKLESS_REPOS" "$SUCKLESS_ICON" | awk -F' ' '{print $1}')
+suckless_changes=$(check_single_repo_status "$SUCKLESS_REPOS" "$SUCKLESS_ICON" | awk -F' ' '{print $2}')
+
+private_status=$(check_multi_repo_status "$PRIVATE_REPOS" "$PRIVATE_ICON" | awk -F' ' '{print $1}')
+private_changes=$(check_multi_repo_status "$PRIVATE_REPOS" "$PRIVATE_ICON" | awk -F' ' '{print $2}')
+
+public_status=$(check_multi_repo_status "$PUBLIC_REPOS" "$PUBLIC_ICON" | awk -F' ' '{print $1}')
+public_changes=$(check_multi_repo_status "$PUBLIC_REPOS" "$PUBLIC_ICON" | awk -F' ' '{print $1}')
+
+[ -f /tmp/gitsync ] && rm -f /tmp/gitsync
+
+# Combine statuses
+output=""
+[ -n "$dotfiles_status" ] && output+="$dotfiles_status "
+[ -n "$suckless_status" ] && output+="$suckless_status "
+[ -n "$private_status" ] && output+="$private_status "
+[ -n "$public_status" ] && output+="$public_status "
+
+# Trim trailing spaces and display output
+output="${output%"${output##*[! ]}"}"
+[ -n "$output" ] && (cat /tmp/gitsync 2>/dev/null || echo "$output")
+
+openrepos() {
+ all_changed_repos="$dotfiles_changes"$'\n'"$suckless_changes"$'\n'"$private_changes"$'\n'"$public_changes"
+ [ -n "$all_changed_repos" ] && exec "$TERMINAL" -e opensessions "$(echo "$all_changed_repos" | grep -v '^$')"
+}
+
+# Handle button actions
+case "$BLOCK_BUTTON" in
+1) openrepos ;;
+3) notify-send "ο‚› Git module" "\- Shows git repositories changes
+- Left click opens changed repositories" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;; # Launch editor for the script
+esac
diff --git a/ar/.local/bin/statusbar/sb-tasks b/ar/.local/bin/statusbar/sb-tasks
new file mode 100755
index 0000000..66be81b
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-tasks
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+# Get the current time and the time in one hour
+now=$(date +%s)
+in_one_hour=$(date -d "+1 hour" +%s)
+
+# Check for tasks due in the next hour
+tasks_due_today=$(task due:tomorrow _ids)
+tasks_due_count=0
+tasks_due_list=""
+
+for task_id in $tasks_due_today; do
+ task_due_date=$(task _get "$task_id".due)
+ task_due_epoch=$(date -d "$task_due_date" +%s)
+ task_description=$(task _get "$task_id".description)
+
+ # Check if the task is due within the next hour
+ if [ "$task_due_epoch" -gt "$now" ] && [ "$task_due_epoch" -le "$in_one_hour" ]; then
+ tasks_due_list="$tasks_due_list- $task_description\n"
+ tasks_due_count=$((tasks_due_count + 1))
+ fi
+done
+
+# Check for overdue tasks (tasks with due date in the past)
+overdue_tasks=$(task +OVERDUE _ids)
+overdue_count=0
+overdue_list=""
+
+for task_id in $overdue_tasks; do
+ task_description=$(task _get "$task_id".description)
+ overdue_list="$overdue_list- $task_description\n"
+ overdue_count=$((overdue_count + 1))
+done
+
+# Check for follow-up tasks
+follow_up_tasks=$(task follow.is:Y _ids -PARENT)
+follow_up_count=0
+follow_up_list=""
+
+for task_id in $follow_up_tasks; do
+ task_due_date=$(task _get "$task_id".due)
+ task_due_epoch=$(date -d "$task_due_date" +%s)
+ task_description=$(task _get "$task_id".description)
+
+ # Ensure that follow-up tasks are only shown if they are not overdue
+ if [ "$task_due_epoch" -ge "$now" ]; then
+ follow_up_list="$follow_up_list- $task_description\n"
+ follow_up_count=$((follow_up_count + 1))
+ fi
+done
+
+check_task_sync() {
+ if [ "$(task _get tw.syncneeded)" -eq 1 ]; then
+ tasks-sync
+ notify-send "πŸ“š Tasks synced"
+ fi
+}
+
+# Handle mouse clicks
+case $BLOCK_BUTTON in
+1) # Combine actions for button 1 and button 2
+ notify-send "πŸ“š Follow-up task(s) to complete:" "$(printf "%b" "$follow_up_list")
+πŸ“• Tasks due in the next hour:
+$(printf "%b" "$tasks_due_list")
+⏰ Overdue Tasks:
+$(printf "%b" "$overdue_list")"
+ ;;
+2) check_task_sync ;;
+3)
+ notify-send "πŸ—‚οΈ Task Module" "Shows task counts.
+- Left click: Show tasks due soon.
+- Middle click: Show follow-up tasks."
+ ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+# Output task information to dwmblocks
+output=""
+
+[ "$overdue_count" -gt 0 ] && output="${output}⏰$overdue_count "
+[ "$follow_up_count" -gt 0 ] && output="${output}πŸ“š$follow_up_count "
+[ "$tasks_due_count" -gt 0 ] && output="${output}πŸ“•$tasks_due_count " && notify-send -u critical "πŸš‘ Tasks Remained!" "$tasks_due_list"
+[ "$(task _get tw.syncneeded)" -eq 1 ] && output="${output}πŸ“‘ "
+echo "${output%* }"
diff --git a/ar/.local/bin/statusbar/sb-torrent b/ar/.local/bin/statusbar/sb-torrent
new file mode 100755
index 0000000..79da88d
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-torrent
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+status=$(transmission-remote -l | grep % |
+ sed " # The letters are for sorting and will not appear
+ s/.*Stopped.*/A πŸ›‘/;
+ s/.*Seeding.*/Z 🌱/;
+ s/.*100%.*/N βœ…/;
+ s/.*Idle.*/B πŸ•°οΈ/;
+ s/.*Uploading.*/L πŸ”Ό/;
+ s/.*%.*/M πŸ”½/" |
+ sort -h | uniq -c | awk '{print $3 $1}' | paste -sd ' ' -)
+
+if [ -z "$status" ]; then
+ echo "$status"
+else
+ pidof transmission-daemon >/dev/null && echo "🌲"
+fi
+
+case $BLOCK_BUTTON in
+1) setsid -f "$TERMINAL" -e stig ;;
+2) td-toggle ;;
+3) notify-send "🌱 Torrent module" "\- Left click to open stig
+- Middle click to toggle transmission
+- Shift click to edit script
+Module shows number of torrents:
+πŸ›‘: paused
+πŸ•°: idle (seeds needed)
+πŸ”Ό: uploading (unfinished)
+πŸ”½: downloading
+βœ…: done
+🌱: done and seeding" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
diff --git a/ar/.local/bin/statusbar/sb-volume b/ar/.local/bin/statusbar/sb-volume
new file mode 100755
index 0000000..800f19e
--- /dev/null
+++ b/ar/.local/bin/statusbar/sb-volume
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Prints the current volume or πŸ”‡ if muted.
+
+case $BLOCK_BUTTON in
+1)
+ setsid -w -f "$TERMINAL" -e pulsemixer
+ pkill -RTMIN+5 "${STATUSBAR:-dwmblocks}"
+ ;;
+2) wpctl set-mute @DEFAULT_SINK@ toggle ;;
+4) wpctl set-volume @DEFAULT_SINK@ 1%+ ;;
+5) wpctl set-volume @DEFAULT_SINK@ 1%- ;;
+3) notify-send "πŸ“’ Volume module" "\- Shows volume πŸ”Š, πŸ”‡ if muted
+- Middle click to mute
+- Scroll to change" ;;
+6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
+esac
+
+vol="$(wpctl get-volume @DEFAULT_AUDIO_SINK@)"
+
+# If muted, print πŸ”‡ and exit.
+[ "$vol" != "${vol%\[MUTED\]}" ] && echo πŸ”‡ && exit
+
+vol="${vol#Volume: }"
+
+split() {
+ # For ommiting the . without calling and external program.
+ IFS=$2
+ set -- $1
+ printf '%s' "$@"
+}
+
+vol="$(printf "%.0f" "$(split "$vol" ".")")"
+
+case 1 in
+$((vol > 100))) icon="πŸ“’" ;;
+$((vol >= 70))) icon="πŸ”Š" ;;
+$((vol >= 30))) icon="πŸ”‰" ;;
+$((vol >= 1))) icon="πŸ”ˆ" ;;
+*) echo πŸ”‡ && exit ;;
+esac
+
+echo "$icon$vol%"