Scripts to Run and Update

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.

xplanet projections

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.

 

5 Responses to Scripts to Run and Update

  1. 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

    • Xplanet Blog says:

      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.

  2. Hari Nair says:

    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

    • Xplanet Blog says:

      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.

Leave a Reply

Your email address will not be published. Required fields are marked *