one 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #!/bin/bash
  2. me="${0##*/}"
  3. ### DEPENDENCIES ###
  4. # coreutils awk sed xset xssstate xplanet
  5. ### RECOMMENDS ###
  6. # cputool feh wget xdpyinfo
  7. # The script fetches a screensaver timeout via xset and might behave unpredictably if that fails.
  8. ###############################################################################
  9. # USER ADJUSTABLE VARIABLES
  10. xplanetdir="$HOME/.xplanet"
  11. imgdir="$xplanetdir/images"
  12. allfeh=1 # set to 1: Use feh for setting the background, not xplanet
  13. tmpfile=/tmp/welrjkht.png
  14. # EARTH MAP
  15. # needs to point to the directory structure created by my get_bluemarble script
  16. bluemarble="$xplanetdir/bluemarble"
  17. prefix="world.topo.bathy" # "world" "world.topo" - the available map variations
  18. suffix="8192x4096_less.png" # resolution and filetype - you probably don't need to change this.
  19. # in the end the image for this month of the year will be linked to $imgdir/earth.jpg, which is what xplanet defaults to
  20. # the scripts directory will be created by this script!
  21. scenes="$xplanetdir/scripts/scenes"
  22. # how ill the scene be chosen from the scene file?
  23. #~ choose_scene="random" # randomly
  24. #~ choose_scene="daily" # daily change the scene, going through $scenes
  25. #~ choose_scene=1 # where n is a positive integer for the nth scene in your scenes file
  26. choose_scene="$1"
  27. delay=60 # sleep between runs/checks
  28. limit=10 # don't let cpu usage go beyond this many percent - only works when cputool is installed
  29. # setting this to 1 makes the script check for a current cloud image and
  30. # download it to the path $cloudimg
  31. # the get_clouds subroutine relies on this repository: github.com/apollo-ng/cloudmap
  32. apollo_ng_clouds=0
  33. # the following options are relevant only when apollo_ng_clouds == 1
  34. # this should be present in your xplanet config:
  35. cloudimg="$imgdir/clouds_5400x2700.jpg"
  36. maxdiff="10800" # if our cloud image is older than that - 3 hours - check if there's a new one
  37. #~ options=( -num_times 1 -date_format %c -color 0x555555 -pango -fontsize 8 \
  38. #~ -font "xos4 terminus" -labelpos +20+50 -glare 0 \
  39. #~ -label_string "Looking at: %t - Origin: %o" )
  40. [[ $allfeh == 1 ]] && options=( -num_times 1 -glare 0 ) || options=( -num_times 1 -glare 0 -transparency )
  41. [[ $allfeh == 1 ]] && geometry="$(xdpyinfo | awk '/dimensions/{print $2}')"
  42. ##############################################################################
  43. # HERE BE LIONS
  44. # sleep as a builtin
  45. for file in /usr/lib*/bash/sleep; do
  46. [ -r "$file" ] && enable -f "$file" sleep && break
  47. done
  48. # Portable enough?
  49. get_clouds() {
  50. # CLOUD MAP for all - praise be:
  51. # apollo.open-resource.org/mission:log:2014:06:17:new-fresh-global-cloudmap-distribution-service-xplanet
  52. # using this function is configurable; set to anything but 1 equals false
  53. [[ "$apollo_ng_clouds" != 1 ]] && return
  54. #~ __msg__ "Checking for a cloud map newer than $cloudimg"
  55. local_age="$(stat -c%Y "$cloudimg")"
  56. now="$(date +%s)"
  57. __msg__ "Local cloudmap age $local_age; time now $now; difference $((now - local_age))s"
  58. if (( now - local_age > 10800 )); then
  59. __msg__ "It's been longer than ${maxdiff}s, time to check if there's a newer one..."
  60. # Get latest remote checksum
  61. originsha=$(wget https://raw.githubusercontent.com/apollo-ng/cloudmap/master/global.sha256 --no-cache -q -O -)
  62. originsha="${originsha%% *}"
  63. # Generate local checksum
  64. if [ -e "$cloudimg" ]; then
  65. localsha="$(sha256sum "$cloudimg")"
  66. localsha="${localsha%% *}"
  67. fi
  68. # Check if we're behind origin
  69. __msg__ "Checksum comparison says remote file is "
  70. if [ "${originsha}" != "${localsha}" ]; then
  71. __msg__ "not the same file as local file; getting it."
  72. newcloudimg="$imgdir/newcloudimg.jpg"
  73. # Download raw global.jpg from master
  74. wget https://raw.githubusercontent.com/apollo-ng/cloudmap/master/global.jpg?${originsha} --no-cache -q -O "$newcloudimg"
  75. # Generate checksum of downloaded file
  76. newsha="$(sha256sum "$newcloudimg")"
  77. newsha="${newsha%% *}"
  78. # Check if download's chksum corresponds to origin
  79. [ "$newsha" == "$originsha" ] && mv "$newcloudimg" "$cloudimg" || rm "$newcloudimg"
  80. else
  81. __msg__ "the same file as local file. Nothing to do."
  82. fi
  83. else
  84. __msg__ "That's not longer than ${maxdiff}s, nothing to do."
  85. fi
  86. __msg__ "Back to main loop."
  87. }
  88. set_bg() {
  89. # if -background is found in options (read from current scene) set it as root window background before xplanet even starts
  90. for ((i=1;i<=$#;i++)); do
  91. [[ "${!i}" == "-background" ]] && ((i++)) && background="${!i}" && break
  92. done
  93. __msg__ "Found background $background"
  94. if [ -r "$background" ]; then
  95. __msg__ feh --no-fehbg --bg-fill "$background"
  96. feh --no-fehbg --bg-fill "$background"
  97. elif [ -r "$imgdir/$background" ];then
  98. __msg__ feh --no-fehbg --bg-fill "$imgdir/$background"
  99. feh --no-fehbg --bg-fill "$imgdir/$background"
  100. fi
  101. }
  102. __msg__() {
  103. echo -e "${me}@${SECONDS}s: $@"
  104. }
  105. aftermath() {
  106. # things to do after root window update
  107. signal=SIGUSR2
  108. for pid in $(pidof root-tail); do
  109. echo "kill -s $signal $pid"
  110. kill -s $signal $pid
  111. done
  112. }
  113. allfehornot() {
  114. if [[ $allfeh == 1 ]]; then
  115. "$@" -output "$tmpfile" -geometry "$geometry"
  116. feh --no-fehbg --bg-tile "$tmpfile"
  117. rm "$tmpfile"
  118. else
  119. "$@"
  120. fi
  121. }
  122. ##############################################################################
  123. # MAIN
  124. sstime="$(xset q | awk '/timeout/ {print $2}')" # the screensaver delay time in s
  125. cputool="$(which cputool)"
  126. [ ! -x "$cputool" ] && cputool=0 && limit=100
  127. # EARTH MAP
  128. month="$(date +%m)"
  129. map_real="$bluemarble/$month/$prefix/$prefix.2004$month.3x$suffix"
  130. map_link="$imgdir/earth.jpg"
  131. if [ ! -a "$map_link" ] || [ -h "$map_link" ]]; then
  132. ln -sf "$map_real" "$map_link"
  133. else
  134. __msg__ "Not symlinking chosen earth map\n$map_real\nto $map_link\nbecause $map_link\nalready exists and is not a symbolic link."
  135. fi
  136. ##############################################################################
  137. # we need to sanitize the scenes file first (mostly because wc -l might return something wrong):
  138. tail -c1 "$scenes" | read -r _ || echo >> "$scenes" # if a trailing newline is missing, add one
  139. sed -i '/^$/d' "$scenes" # if there's empty lines, delete them
  140. allscenes="$(wc -l "$scenes")"
  141. allscenes="$(( ${allscenes%% *} / 2))"
  142. case "$choose_scene" in
  143. random) chosen=$((RANDOM%allscenes + 1));;
  144. daily) chosen=$(($(date +%-j)%allscenes + 1));;# %j: day of the year - so we change the scene once a day
  145. *) if [ "$choose_scene" -gt 0 ] && [ "$choose_scene" -le "$allscenes" ]; then
  146. chosen="$choose_scene"
  147. else
  148. __msg__ "Wrong value for choose_scene: $choose_scene. Exiting."
  149. exit 1
  150. fi;;
  151. esac
  152. __msg__ "Chosen scene #$chosen:"
  153. chosen=$((chosen*2))
  154. sed -n $((chosen - 1))p "$scenes"
  155. eval set -- "$(sed -n ${chosen}p "$scenes")"
  156. __msg__ "All options:\n${options[@]} $@\n"
  157. # if a background image is found in options, set it with feh
  158. set_bg "$@"
  159. aftermath
  160. killall xplanet >/dev/null 2>&1
  161. get_clouds
  162. __msg__ "First xplanet run without CPU throttling ..."
  163. runtime=$SECONDS
  164. ###########################
  165. xplanet "${options[@]}" "$@"
  166. ###########################
  167. aftermath
  168. runtime=$(( SECONDS - runtime)) # a very rough calculation of how long xplanet took without cpu throttling; this is used to determine
  169. # max. idle time before screensaver kicks in
  170. __msg__ "... That took $runtime seconds"
  171. (( runtime == 0 )) && runtime=1
  172. runtime=$(( runtime * (100/limit) ))
  173. __msg__ "Screensaver delay according to xset: ${sstime}s\nCalculated xplanet runtime with CPU usage limited to ${limit}%: ${runtime}s"
  174. # assume xplanet takes Xs to render things, so if the screensaver comes on in Xs, don't even start rendering
  175. (( sstime > runtime )) && sstime="$((sstime - runtime))" || sstime="$runtime"
  176. __msg__ "If idle for more than ${sstime}s do not start xplanet.\n"
  177. sstime="$((sstime * 1000))" # need it in ms
  178. while sleep "$delay"; do
  179. # X11 has been idle for too long?
  180. idle="$(xssstate -i)"
  181. __msg__ "Current idle time: $((idle / 1000))s"
  182. if (( idle > sstime )); then
  183. __msg__ "Not running xplanet because screensaver is going to activate soon."
  184. else
  185. if [[ "$cputool" != 0 ]] && ((limit<100)); then
  186. __msg__ "Starting throttled xplanet"
  187. allfehornot cputool -c $limit -- xplanet "${options[@]}" "$@"
  188. else
  189. __msg__ "Starting xplanet"
  190. allfehornot xplanet "${options[@]}" "$@"
  191. fi
  192. __msg__ "xplanet finished"
  193. aftermath
  194. fi
  195. get_clouds
  196. done