i3_lemonbar.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #!/bin/bash
  2. ## I3 bar with https://github.com/LemonBoy/bar
  3. ##
  4. ## Based on Electro7's work
  5. ## Modded by demure
  6. . $(dirname $0)/i3_lemonbar_config
  7. if [ $(pgrep -cx $(basename $0)) -gt 1 ] ; then
  8. printf "%s\n" "The status bar is already running." >&2
  9. exit 1
  10. fi
  11. trap 'trap - TERM; kill 0' INT TERM QUIT EXIT
  12. [ -e "${panel_fifo}" ] && rm "${panel_fifo}"
  13. mkfifo "${panel_fifo}"
  14. ### EVENTS METERS
  15. ## Window title, "WIN"
  16. xprop -spy -root _NET_ACTIVE_WINDOW | sed -un 's/.*\(0x.*\)/WIN\1/p' > "${panel_fifo}" &
  17. ## i3 Workspaces, "WSP"
  18. ## TODO : Restarting I3 breaks the IPC socket con. :(
  19. $(dirname $0)/i3_workspaces.pl > "${panel_fifo}" &
  20. # IRC, "IRC"
  21. # only for init
  22. #~/bin/irc_warn &
  23. ## Conky, "SYS"
  24. conky -c $(dirname $0)/i3_lemonbar_conky > "${panel_fifo}" &
  25. ### UPDATE INTERVAL METERS
  26. cnt_vol=${upd_vol}
  27. cnt_bri=${upd_bri}
  28. cnt_mail=${upd_mail}
  29. cnt_mmpd=${upd_mmpd}
  30. cnt_ext_ip=${upd_ext_ip}
  31. cnt_gpg=${upd_gpg}
  32. cnt_tmb=${upd_tmb}
  33. cnt_temp=${upd_temp}
  34. cnt_net=${upd_net}
  35. cnt_mem=${upd_mem}
  36. cnt_time=${upd_time}
  37. cnt_disk=${upd_disk}
  38. cnt_rss=${upd_rss}
  39. while :; do
  40. ### Volume Check, "VOL" ### {{{
  41. if [ $((cnt_vol++)) -ge ${upd_vol} ]; then
  42. ## Retired this line as amixer stopped showing >100% volume... around the same time amixer mute broke
  43. #amixer get Master | awk -F'[]%[]' '/%/ {STATE=$5; VOL=$2} END {if (STATE == "off") {print "VOL×\n"} else {printf "VOL%d%%\n", VOL}}' > "${panel_fifo}" &
  44. pactl list sinks | awk 'BEGIN {MUTE="none";VOL="none"}/^\t*Volume|^\t*Mute/ {if($1=="Mute:"){MUTE=$2};if($1=="Volume:"){VOL=$5}} END {if(MUTE=="yes"){print "VOL×\n"} else {if(VOL!="none"){printf "VOL%d%%\n", VOL} else {print "VOLerror\n"};}}' > "${panel_fifo}" &
  45. cnt_vol=0
  46. fi
  47. ### End Volume Check, "VOL" ### }}}
  48. ### Brightness Check, "BRI" ### {{{
  49. if [ $((cnt_bri++)) -ge ${upd_bri} ]; then
  50. ## xbacklight doesn't work as this doesn't have xrandr access while running as the bar?
  51. ## On failure, '$1/$2' becomes '0', and will result in 'none'
  52. printf "%s%s\n" "BRI" "$(paste /sys/class/backlight/*/{actual_brightness,max_brightness} | awk '{BRIGHT=$1/$2*100} END {if(BRIGHT!=0){printf "%.f", BRIGHT} else {print "none"}}')" > "${panel_fifo}"
  53. cnt_bri=0
  54. fi
  55. ### End Brightness Check, "BRI" ### }}}
  56. ### Temperature Check, "TMP" ### {{{
  57. if [ $((cnt_temp++)) -ge ${upd_temp} ]; then
  58. ## Removes decimal from Celsius as it is always an integer
  59. printf "%s%s\n" "TMP" "$(acpi -t${temp_format} 2>/dev/null | awk 'BEGIN {} /Thermal 0/ {if($6=="C"){printf "%.0f %s",$4,$6} else {if($6=="F"){print $4,$6} else {print "none none"};}}')" > "${panel_fifo}"
  60. cnt_temp=0
  61. fi
  62. ### End Temperature Check, "TMP" ### }}}
  63. ### Network Check, "NET" ### {{{
  64. if [ $((cnt_net++)) -ge ${upd_net} ]; then
  65. ## Get IP and wifi strength
  66. ## Now supports IPv6
  67. ## Now filters out virtual interfaces for docker/qemu/vpn
  68. printf "%s%s %s %s\n" "NET" "$(ip address show up scope global 2>/dev/null | awk 'BEGIN {Dv4=0;Dv6=0} /inet/&&!/(docker|virbr|tun|tap)[0-9]+$/ {if(Dv4==0 && $1=="inet"){sub(/\/.*/,NULL,$2); IPv4=$2; INT=$7; Dv4=1}; if(Dv6==0 && $1=="inet6" && $2!~/^fd/){sub(/\/.*/,NULL,$2); IPv6=$2; Dv6=1}} END {if(IPv4==""){IPv4="none"; INT="none"}; if(IPv6==""){IPv6="none"}; print IPv4,INT,IPv6}')" "$(iwconfig 2>/dev/null | awk '/Link/ {match($2, /\w+=([0-9]+)\/([0-9]+)/, m)} END {if(m[1]!=""&&m[2]!=""){print int((m[1] / m[2]) * 100)} else {print "none"}}')" "$(ip tuntap | awk 'BEGIN {TC=0} /tun/ {if($0!=""){TC++}} END {if(TC>=1){print "VPN"} else {print "none"}}')" > "${panel_fifo}"
  69. cnt_net=0
  70. fi
  71. ### End Network Check, "NET" ### }}}
  72. ### Offlineimap, "EMA" ### {{{
  73. if [ $((cnt_mail++)) -ge ${upd_mail} ]; then
  74. printf "%s%s\n" "EMA" "$(find ${HOME}/.mail/*/INBOX/new -type f 2>/dev/null | wc -l)" > "${panel_fifo}"
  75. cnt_mail=0
  76. fi
  77. ### End Offlineimap, "EMA" ### }}}
  78. ### Multi Music Player Display, "MMP" ### {{{
  79. if [ $((cnt_mmpd++)) -ge ${upd_mmpd} ]; then
  80. mmpd_check="$(grep -qxs 1 ${HOME}/.config/pianobar/isplaying && cat ${HOME}/.config/pianobar/nowplaying || echo 'none')"
  81. if [ "${mmpd_check}" != "none" ]; then
  82. printf "%s%s\n" "MMP" "${mmpd_check}" > "${panel_fifo}"
  83. else
  84. ## cmus
  85. mmpd_check="$(cmus-remote -Q 2>/dev/null | awk 'BEGIN {STATUS=0;STREAM=0;TITLE=0;ARTIST=0} {match($0, /^(status|stream|tag title|tag artist)\s(.*)/, m); if(m[1]=="status"){STATUS=m[2]};if(m[1]=="stream"){STREAM=m[2]}; if(m[1]=="tag title"){TITLE=m[2]}; if(m[1]=="tag artist"){ARTIST=m[2]}} END {if(STATUS!=0){if(STATUS=="playing"){if(STREAM!=0){print STREAM} else if(ARTIST!=0&&TITLE!=0){print ARTIST " - " TITLE} else if(TITLE!=0){print TITLE}else {print "cmus: no meta data"}} else if(STATUS=="paused"){print "cmus: paused"} else {print "none"}} else {print "none"}}')"
  86. if [ "${mmpd_check}" != "none" ]; then
  87. printf "%s%s\n" "MMP" "${mmpd_check}" > "${panel_fifo}"
  88. else
  89. ## mpd
  90. ## Note this is my own mpd check (not elctro7's)
  91. ## It will report if mpd is paused.
  92. mmpd_check="$(mpc status 2>/dev/null | awk 'BEGIN {STATUS=0;INFO=0} !/^volume/ {match($0, /^(\w+.*)/, p); match($0, /(\[playing\]|\[paused\])/, m); if(m[0]!=""){STATUS=m[1]}; if(p[0]!=""){INFO=p[0]}} END {if(STATUS!=0){if(STATUS=="[paused]"){print "mpd: paused"} else {print INFO}} else {print "none"}}')"
  93. if [ "${mmpd_check}" != "none" ]; then
  94. printf "%s%s\n" "MMP" "${mmpd_check}" > "${panel_fifo}"
  95. else
  96. ## mocp
  97. mmpd_check="$(mocp --info 2>/dev/null | awk 'BEGIN {STATE=0; TITLE=0; ARTIST=0} {match($0, /^(State|Title|Artist):\s(.*)/, m); if(m[1]=="State"){STATE=m[2]}; if(m[1]=="Artist"&&m[2]!=""){ARTIST=m[2]}; if(m[1]=="Title"&&m[2]!=""){TITLE=m[2]}} END {if(STATE!=0){if(STATE=="PLAY"){if(TITLE!=0){print TITLE} else {print "mocp: no meta data"}} else if(STATE=="PAUSE"){print "mocp: paused"} else {print "none"}} else {print "none"}}')"
  98. if [ "${mmpd_check}" != "none" ]; then
  99. printf "%s%s\n" "MMP" "${mmpd_check}" > "${panel_fifo}"
  100. else
  101. ## audacios
  102. mmpd_check="$(audtool --playback-status --current-song 2>/dev/null | awk 'BEGIN {STATUS=0; INFO=0} {if($0=="playing"||$0=="paused"){STATUS=$0}; if(STATUS=="playing"){INFO=$0}} END {if(INFO!=0){print INFO} else if(STATUS=="paused"){print "audacios: paused"} else {print "none"}}')"
  103. if [ "${mmpd_check}" != "none" ]; then
  104. printf "%s%s\n" "MMP" "${mmpd_check}" > "${panel_fifo}"
  105. else
  106. ## This makes scaling easier
  107. printf "%s%s\n" "MMP" "none" > "${panel_fifo}"
  108. fi
  109. fi
  110. fi
  111. fi
  112. fi
  113. cnt_mmpd=0
  114. fi
  115. ### End Multi Music Player Display ### }}}
  116. ### Thinkpad Milti Battery, "TMB" ### {{{
  117. ## Works for normal batteries now too.
  118. if [ $((cnt_tmb++)) -ge ${upd_tmb} ]; then
  119. ## Check for BAT0
  120. if [ -e /sys/class/power_supply/BAT0/uevent ]; then
  121. BAT0="/sys/class/power_supply/BAT0/uevent"
  122. else
  123. BAT0=""
  124. fi
  125. ## Check for BAT1
  126. if [ -e /sys/class/power_supply/BAT1/uevent ]; then
  127. BAT1="/sys/class/power_supply/BAT1/uevent"
  128. else
  129. BAT1=""
  130. fi
  131. if [ "${BAT0}" != "" ] || [ "${BAT1}" != "" ]; then
  132. ## Originally "/sys/class/power_supply/BAT{0..1}/uevent" but changed into variables make work for non thinkpad cases. paste fails if it can't find a passed file.
  133. ## "U" for unknown
  134. printf "%s%s %s\n" "TMB" "$(paste -d = ${BAT0} ${BAT1} 2>/dev/null | awk 'BEGIN {CHARGE="U"} /ENERGY_FULL=/||/ENERGY_NOW=/||/STATUS=/||/CHARGE_NOW=/||/CHARGE_FULL=/ {split($0,a,"="); if(a[2]~/Discharging/||a[4]~/Discharging/){CHARGE="D"} else if(a[2]~/Charging/||a[4]~/Charging/){CHARGE="C"} else if (a[2]~/Full/||a[4]~/Full/){CHARGE="F"}; if(a[1]~/FULL/){FULL=a[2]+a[4]}; if(a[1]~/NOW/){NOW=a[2]+a[4]};} END {if(NOW!=""){PERC=int((NOW/FULL)*100)} else {PERC="none"}; printf("%s %s\n", PERC, CHARGE)}')" "$(acpi -b | awk '/[0-9]+:[0-9]+:[0-9]+ (until|remaining)/ {if($5!=""){split($5,s,":");if(s[1]!="00"){HOUR=s[1]"h"};if(s[2]!="00"){MIN=s[2]"m"};TIME=HOUR MIN}} END {if(TIME!=""){print TIME} else {print "none"}}')" > "${panel_fifo}"
  135. else
  136. printf "%s%s\n" "TMB" "none" > "${panel_fifo}"
  137. fi
  138. cnt_tmb=0
  139. fi
  140. ### End Thinkpad Milti Battery, "TMB" ### }}}
  141. ### GPG Cache Check, "GPG" ### {{{
  142. if [ $((cnt_gpg++)) -ge ${upd_gpg} ]; then
  143. export DISPLAY=''
  144. ## Now will check if a local gpg key, or a smartcard, is cached.
  145. printf "%s%s\n" "GPG" "$({ gpg-connect-agent 'keyinfo --list' /bye 2>/dev/null; gpg-connect-agent 'scd getinfo card_list' /bye 2>/dev/null; } | awk 'BEGIN{CH=0} /^S/ {if($7==1){CH=1}; if($2=="SERIALNO"){CH=1}} END{if($0!=""){print CH} else {print "none"}}')" > "${panel_fifo}"
  146. cnt_gpg=0
  147. fi
  148. ### End GPG Cache Check, "GPG" ### }}}
  149. ### External IP Check, "EXT" ### {{{
  150. if [ $((cnt_ext_ip++)) -ge ${upd_ext_ip} ]; then
  151. printf "%s%s\n" "EXT" "$(wget --no-proxy http://checkip.dyndns.org/ -q -O - | grep -Eo '\<[[:digit:]]{1,3}(\.[[:digit:]]{1,3}){3}\>' || echo 'err')" > "${panel_fifo}"
  152. cnt_ext_ip=0
  153. fi
  154. ### End External IP Check, "EXT" ### }}}
  155. ### System Memory Usage, "MEM" ### {{{
  156. if [ $((cnt_mem++)) -ge ${upd_mem} ]; then
  157. ## Using MemAvailable and flipping the percentage with a "1-__" as MemFree gives bad results.
  158. printf "%s%s\n" "MEM" "$(awk '/MemAvailable/ {AVAIL=$2} /MemTotal/ {TOTAL=$2} END {printf "%.0f%\n", (1-AVAIL/TOTAL)*100}' /proc/meminfo)" > "${panel_fifo}"
  159. cnt_mem=0
  160. fi
  161. ### End System Memory Usage, "MEM" ### }}}
  162. ### Time Check, "TIM" ### {{{
  163. if [ $((cnt_time++)) -ge ${upd_time} ]; then
  164. printf "%s%s\n" "TIM" "$(date '+%a %d %b %H:%M')" > "${panel_fifo}"
  165. printf "%s%s\n" "UTC" "$(date -u '+%F %H:%M UTC')" > "${panel_fifo}"
  166. cnt_time=0
  167. fi
  168. ### End Time Check, "TIM" ### }}}
  169. ### Disk Usage Check, "DIC" ### {{{
  170. if [ $((cnt_disk++)) -ge ${upd_disk} ]; then
  171. ## Limits to root filesystem. awk cuts header line and shucks leading space
  172. printf "%s%s\n" "DIC" "$(df --output=pcent / | awk 'END {print $1}')" > "${panel_fifo}"
  173. cnt_disk=0
  174. fi
  175. ### End Disk Usage Check, "DIC" ### }}}
  176. ### RSS Unread Check, "RSS" ### {{{
  177. if [ $((cnt_rss++)) -ge ${upd_rss} ]; then
  178. ## Checks that $rss_path is set or skips commands
  179. if [ -n "${rss_path}" ]; then
  180. ## Verifies that sqlite3 is installed
  181. if [ -n "$(command -v sqlite3)" ]; then
  182. ## Polls newsboat db for unread count.
  183. printf "%s%s\n" "RSS" "$(sqlite3 ${rss_path} 'select sum(unread) from rss_item')" > "${panel_fifo}"
  184. fi
  185. fi
  186. cnt_rss=0
  187. fi
  188. ### End RSS Unread Check, "RSS" ### }}}
  189. ## Finally, wait 1 second
  190. sleep 1s;
  191. done &
  192. #### LOOP FIFO
  193. cat "${panel_fifo}" | $(dirname $0)/i3_lemonbar_parser.sh \
  194. | lemonbar -p -f "${font}" -f "${iconfont}" -g "${geometry}" -B "${color_back}" -F "${color_fore}" &
  195. wait