The below files and scripts are used to update data that changes frequently, e.g., the Earth map, the cloud map, and TotalMarker marker files and to automate the execution of Xplanet. Copy and save the contents of each file into the specified location.
Definitions File
File Location: ~/.xplanet/personal/definitions
This file defines most of the variables that are used in the main script. I broke it out from the actual script to allow experimentation without worrying about breaking the core script Xplanet relies upon to start and update.
Optional variables you should experiment with include the projection, longitude, and minimum earthquake size.
XPLANET_HOME=/Users/$USER/.xplanet XPLANET_PERSONAL=${XPLANET_HOME}/personal XPLANET_SCRIPTS=${XPLANET_PERSONAL}/scripts XPLANET_TEMP=${XPLANET_SCRIPTS}/temp XPLANET_PROJECTION=rectangular XPLANET_GEOMETRY=1920x1080 XPLANET_LONGITUDE=0 EARTH_MAP_PRE=world #EARTH_MAP_PRE=world.topo #EARTH_MAP_PRE=world.topo.bathy CLOUD_URL=http://xplanetclouds.com/free/coral #CLOUD_URL=http://xplanetclouds.com/free/local #CLOUD_URL=http://xplanetclouds.com/clouds/2048 CLOUD_MAP=clouds_2048.jpg CLOUD_USER=[username] CLOUD_PWD=[password] TOTALMARKER_URL=http://www.wizabit.eclipse.co.uk/xplanet/files/local QUAKE_MIN=4 SCRIPT_QUAKE=${XPLANET_SCRIPTS}/quake.rb SCRIPT_LABEL=${XPLANET_SCRIPTS}/label.rb
Projections
Xplanet offers a total of 16 different projections you can specify and are shown below.
Scripts to Start and Update Xplanet
File Location: ~/.xplanet/personal/scripts/xplanet.sh
The script in entirety is available here. I’ve broken it up into the main sections below to provide explanations.
header
#!/bin/bash SWITCH=$1 source /Users/$USER/.xplanet/personal/definitions
This section captures the command-line argument and sets the environment by sourcing the definitions file.
help
if [[ ${SWITCH} == 'help' ]]; then echo "Options for this script:" echo " 'start' - starts Xplanet in fork mode" echo " 'stop' - stops all running instances of XPlanet" echo " 'earth' - updates the monthly Earth map" echo " 'clouds' - updates the cloud map" echo " 'quake' - updates the quake marker" echo " 'storm' - updates the storm marker" echo " 'volcano' - updates the volcano marker" echo " 'label' - downloads TotalMarker's label in case required to debug" echo " and also creates a custom label marker" echo " 'help' - prints out this list" echo "" fi
Here we display the acceptable arguments with a brief explanation.
start
if [[ ${SWITCH} == 'start' ]]; then /usr/local/bin/xplanet \ -searchdir=${XPLANET_HOME} \ -config=config \ -projection=${XPLANET_PROJECTION} \ -longitude=${XPLANET_LONGITUDE} \ -labelpos=+10-45 \ -date_format="%D at %r" \ -color=green2 \ -fork echo "$(date): Xplanet Started" fi
Here we execute and fork Xplanet using the variables defined in the definitions file. I have to define the searchdir option since I’m using ~/.xplanet and not Xplanet’s default OS X home directory. As an aside, if you are interested in learning more about the available command line options Xplanet offers or ever need additional help (these are not in the script, but placed here for reference)…
man xplanet # Provides detailed descriptions on the command line options xplanet --help # Lists the available command line options
stop
if [[ ${SWITCH} == 'stop' ]]; then killall xplanet echo "$(date): Xplanet Stopped" fi
The stop switch should kill all running Xplanet instances.
earth
if [[ ${SWITCH} == 'earth' ]]; then MONTH=$(date +%m) LAND_FILE="${EARTH_MAP_PRE}.2004$MONTH.3x5400x2700.png" unlink ${XPLANET_HOME}/images/earth.png ln -s ${XPLANET_PERSONAL}/images/$LAND_FILE ${XPLANET_HOME}/images/earth.png echo "$(date): Earth Map Updated" fi
This part of the script ensures we’re using the land map that corresponds to the current month.
clouds
if [[ ${SWITCH} == 'clouds' ]]; then REMOTEFILE=${CLOUD_MAP} # TEMP="-u ${CLOUD_USER}:${CLOUD_PWD} -z ${XPLANET_TEMP}/${REMOTEFILE}.old -R -o ${XPLANET_TEMP}/${REMOTEFILE} ${CLOUD_URL}/${REMOTEFILE}" # for redirected cloud images, add the "-L" option to curl switched TEMP="-z ${XPLANET_TEMP}/${REMOTEFILE}.old -R -L -o ${XPLANET_TEMP}/${REMOTEFILE} ${CLOUD_URL}/${REMOTEFILE}" curl $TEMP if [[ -a ${XPLANET_TEMP}/${REMOTEFILE} ]]; then cp ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_HOME}/images/${REMOTEFILE} mv ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_TEMP}/${REMOTEFILE}.old echo "$(date): Cloud Map Updated" else echo "$(date): Cloud Map Not Downloaded" fi fi
Here we check for and download any updates to the cloud image. I’ve included a way to access the cloud image Hari makes available for free through the Coral distribution network and another way – commented – to download the images produced every three hours if you decide to purchase a subscription.
quake
if [[ ${SWITCH} == 'quake' ]]; then REMOTEFILE="quake" TEMP="-z ${XPLANET_TEMP}/${REMOTEFILE}.old -R -o ${XPLANET_TEMP}/${REMOTEFILE} ${TOTALMARKER_URL}/${REMOTEFILE}" curl $TEMP if [[ -a ${XPLANET_TEMP}/${REMOTEFILE} ]]; then ${SCRIPT_QUAKE} ${QUAKE_MIN} ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_HOME}/markers/${REMOTEFILE} mv ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_TEMP}/${REMOTEFILE}.old echo "$(date): Quake Marker Updated" else echo "$(date): Quake Marker Not Downloaded" fi fi
Here we check for and download any updates to TotalMarker’s quake marker file. If there’s an update, we run it through a Ruby script to display earthquakes that meet the minimum size requirement in the definitions file.
storm
if [[ ${SWITCH} == 'storm' ]]; then REMOTEFILE="storm" TEMP="-z ${XPLANET_TEMP}/${REMOTEFILE}.old -R -o ${XPLANET_TEMP}/${REMOTEFILE} ${TOTALMARKER_URL}/${REMOTEFILE}" curl $TEMP if [[ -a ${XPLANET_TEMP}/${REMOTEFILE} ]]; then curl -R -o ${XPLANET_HOME}/arcs/${REMOTEFILE} ${TOTALMARKER_URL}/arcs/${REMOTEFILE} cp ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_HOME}/markers/${REMOTEFILE} mv ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_TEMP}/${REMOTEFILE}.old echo "$(date): Storm Marker Updated" else echo "$(date): Storm Marker Not Downloaded" fi fi
Similarly, we check for and download any update to TotalMarker’s storm marker file. If there’s an update, we also download the arc file. The marker file has the storms’ current location. The arc file shows the paths of the storms, both past and anticipated.
volcano
if [[ ${SWITCH} == 'volcano' ]]; then REMOTEFILE="volcano" TEMP="-z ${XPLANET_TEMP}/${REMOTEFILE}.old -R -o ${XPLANET_TEMP}/${REMOTEFILE} ${TOTALMARKER_URL}/${REMOTEFILE}" curl $TEMP if [[ -a ${XPLANET_TEMP}/${REMOTEFILE} ]]; then cp ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_HOME}/markers/${REMOTEFILE} mv ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_TEMP}/${REMOTEFILE}.old echo "$(date): Volcano Marker Updated" else echo "$(date): Volcano Marker Not Downloaded" fi fi
Here we update TotalMarker’s volcano marker file showing active volcanoes.
label
if [[ ${SWITCH} == 'label' ]]; then REMOTEFILE="updatelabel" TEMP="-z ${XPLANET_TEMP}/${REMOTEFILE}.old -R -o ${XPLANET_TEMP}/${REMOTEFILE} ${TOTALMARKER_URL}/${REMOTEFILE}" curl $TEMP if [[ -a ${XPLANET_TEMP}/${REMOTEFILE} ]]; then cp ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_HOME}/markers/${REMOTEFILE} mv ${XPLANET_TEMP}/${REMOTEFILE} ${XPLANET_TEMP}/${REMOTEFILE}.old echo "$(date): Label Marker Updated" else echo "$(date): Label Marker Not Downloaded" fi # UPDATE PERSONAL LABELS ${SCRIPT_LABEL} ${XPLANET_HOME}/ ${XPLANET_TEMP}/ label ${CLOUD_MAP} quake storm volcano fi
Here we download TotalMarker’s label marker, but this is for debugging purposes. More importantly, this section will call a Ruby script to generate a label marker that Xplanet will use on its rendering.
File Location: ~/.xplanet/personal/scripts/quake.rb
The default TotalMarker quake marker file displays all of the Earth’s earthquakes. This is a short and simple script that xplanet.sh calls to create a new marker file that only lists earthquakes meeting a minimum size.
#!/usr/bin/env ruby require 'bigdecimal' quake_min = BigDecimal.new(ARGV[0]) input_file = File.new(ARGV[1], "r") output_file = File.new(ARGV[2], "w") while (line = input_file.gets) # make sure we're not dealing with a commented line if line[0,1] != "#" # is the line an earthquake reference if line.include? '""' # need to grab second line... quake_size_line = input_file.gets # ... get the quake size... /"(.*?)"/.match(quake_size_line) quake_size = BigDecimal.new($1) # ... and check to see if it meets the min size if quake_size >= quake_min # write out the quake markers to the marker file output_file.puts(line) output_file.puts(quake_size_line) end end end end input_file.close output_file.close
File Location: ~/.xplanet/personal/scripts/label.rb
This script is ugly (surprising full disclosure: I’m not a Ruby programmer), but xplanet.sh uses it to generate a marker file indicating the age of the cloud map and TotalMarker markers and when those files were downloaded. It also color codes the labels based on each marker’s age.
#!/usr/bin/env ruby $xplanet_home = ARGV[0] $xplanet_temp = ARGV[1] $marker_label = ARGV[2] $marker_cloud = ARGV[3] $marker_quake = ARGV[4] $marker_storm = ARGV[5] $marker_volcano = ARGV[6] pos_lin1 = "-100 -20 " pos_lin2 = "-85 -20 " pos_lin3 = "-70 -20 " pos_lin4 = "-55 -20 " def create_label_string (marker_f, marker_s, position, marker_o, red_thresh, yellow_thresh) temp_string = position standard_ending = " image=none position=pixel" if File::exists?(marker_f) line_color = "Blue" ts_o = File::mtime(marker_o) ts_n = Time.now age = ((ts_n - ts_o)/60/60).to_i if (age >= red_thresh) line_color = "Red" elsif (age < yellow_thresh) line_color = "Green" else line_color = "Yellow" end timestamp_o = ts_o.strftime("%D at %r") timestamp_d = File::mtime(marker_f).strftime("%D at %r") temp_string = temp_string + "\"" + marker_s + " updated " + timestamp_o + "; downloaded " + timestamp_d + "\" color=" + line_color + standard_ending else temp_string = temp_string + "\"" + marker_s + " has not been downloaded\" color=Red" + standard_ending end return temp_string end # need to make sure we're pointing to the correct marker files and temp marker files # and that we've correctly set the upper and lower thresholds label_file = File.new($xplanet_home+"markers/"+$marker_label, "w") label_file.puts create_label_string($xplanet_home+"images/"+$marker_cloud, "Cloud Map", pos_lin1, $xplanet_temp+$marker_cloud+".old", 24, 6) label_file.puts create_label_string($xplanet_home+"markers/"+$marker_quake, "Earthquake Data from TotalMarker", pos_lin2, $xplanet_temp+$marker_quake+".old", 24, 6) label_file.puts create_label_string($xplanet_home+"markers/"+$marker_storm, "Storm Data from TotalMarker", pos_lin3, $xplanet_temp+$marker_storm+".old", 24, 6) label_file.puts create_label_string($xplanet_home+"markers/"+$marker_volcano, "Volcano Data from TotalMarker", pos_lin4, $xplanet_temp+$marker_volcano+".old", 120, 48) ### label_file.close
Feel free to play around with the “pos_lin” variables for your screen size/resolution. These are set to display toward the bottom right of your screen. They follow the same format as Xplanet’s command line labelpos setting so you can, for example, set the position to +20-100 to display in the bottom left.
Also play around with the threshold setting in the vary end of the file. These numbers define, in hours, how current the various markers our. So the earthquake marker is green if it has been udpated within six hours, yellow between six and 24 hours, and red if it’s older than a day old.
At this point, we’re going to change the permissions for the three scripts so that we can update the Earth map, the cloud map, and the TotalMarker marker files. I like to use the temp directory as my working directory.
chmod 744 ~/.xplanet/personal/scripts/* cd ~/.xplanet/personal/scripts/temp ../xplanet.sh earth ../xplanet.sh clouds ../xplanet.sh quake ../xplanet.sh volcano ../xplanet.sh storm ../xplanet.sh label
The temp directory should now hold five files, and the ~/.xplanet/images directory should expand from three to five files. Double check and make sure you can open up the earth map symlink.
Config File
File Location: ~/.xplanet/config
Xplanet calls the config file to understand which planetary bodies to display and how to represent those bodies. This is an example config file. Xplanet also ships with examples that you can access at /usr/local/share/xplanet/config.
At this point, the map images and marker files have been downloaded and placed in the correct location in the Xplanet home directory. Make sure the five map locations and the five marker locations are valid.
Changes to this file require an Xplanet restart.
[earth] "Earth" map=earth.jpg night_map=lights.tiff cloud_map=clouds_2048.jpg cloud_threshold=45 cloud_gamma=.75 bump_map=bump.jpg bump_scale=2 specular_map=specular.png marker_file=earth marker_file=quake marker_file=volcano marker_file=storm arc_file=storm marker_file=label
In addition to the map and marker links, I also use the cloud_threshold, cloud_gamma, and bump_scale settings. There are many other options you can include in the config file. These are documented in the /usr/local/share/xplanet/config/README file or at the Xplanet homepage.
At this point, you can manually run Xplanet using the script.
cd ~/.xplanet/personal/scripts/temp ../xplanet.sh start
Remember that this forks Xplanet. You can now manually run Xplanet and update the maps and markers as often as needed.
Thanks for publishing this tutorial! I just switched back to a mac (from running xmonad on linux for years) and I’m glad xplanet is still functional — it was my go-to background for many years before I started using tiling window managers.
I often use my mac with multiple monitors (it’s a retina macbook that docks to assorted other display devices). Xplanet only seems to draw the background of the currently focused space on the built-in display. Do you know if it’s possible to draw to all spaces, regardless of the display?
Thanks!
Rogan
Thanks, Rogan. Glad this has been helpful. I was hoping Mavericks would allow for more control to draw Xplanet to a specific display, but it appears it still operates like (Mountain) Lion: always drawing to the display #1. It doesn’t appear to matter to OS X which display is live or which display is displaying the dock. Just speculating, but I can only imagine this functionality to be dependent on Aqua. You might potentially be able to get around this limitation and render Xplanet on a secondary display if you compile Xplanet to use X11 instead of Aqua (brew install xplanet –with-x). Sorry I couldn’t be more helpful.
I stumbled across a rather inelegant workaround, but it’s sufficing for now.
I have xplanet set up to generate a new jpg (named with the current timestamp) every 15 minutes (via a plist file). That script first clears all images from the target directory so that the directory only ever contains one file with a unique name.
Then, I set each OS X desktop background to as slideshow, using the target directory as the image source, and set to change backgrounds every minute.
This only changes backgrounds when you’re actively on the desktop, so when you switch to a new desktop, there may be a slight delay (up to 1 minute) before the background updates, but it’s good enough.
Hi – I’m the author of Xplanet. This guide is really excellent! I use a Mac with multiple monitors too. I do pretty much the same thing that Rogan does. I write out PNG files for each display into separate folders with unique names, then I have OSX update the background from those folders every minute. Apparently OSX won’t update the background unless the image filename has changed. So I use Xplanet’s -post_command option to run a script to rename the image file with a random name, like this:
xplanet -output xplanet.png -post_command rotateName.bash
rotateName.bash:
#!/bin/bash
/bin/rm ?????.png
/bin/mv xplanet.png $(printf %05d ${RANDOM}).png
Hari, Rogan, thank you both for you suggestions. Appreciate your feedback. I’m going to play around with this on my second screen and add a section that covers the best way to do this on OS X.