Ted Wise header image 2

Geek Tool 

Copy ShortURL

February 24th, 2009 · View Comments · Mac

I ran into a line of posts the other day about customizing Mac desktops. There were quite a few interesting ideas but the ones that stuck out for me were the people making use of Geek Tool.

Geek Tool is an OS/X preference pane that allows you to place pretty much anything on the desktop. And what it places on the desktop can be easily formatted. I took one of the designs and extended it slightly to create this:

This time/date/weather display is updated dynamically on the desktop and uses very little CPU.1

Each element in the display is a separate shell command. The elements are:

Element Shell Command Font Location Size Update Period (sec)
The day date +%A Helvetica, Regular, 27point with drop shadow 10x, 727y 200w x 40h 60
The month date +%B Helvetica, Regular, 36point with drop shadow 10x, 750y 200w x 50h 60
The day of the month date +%d Helvetica, Regular, 64point with drop shadow 210x, 720y 100w x 80h 60
The time date "+%I:%M" Helvetica, Bold, 72point with drop shadow 20x, 780y 200w x 80h 10
am/pm date +%p Helvetica, Regular, 48point with drop shadow 210x, 785y 100w x 70h 10
The temperature <bin>/weather.rb -t Helvetica, Bold, 18point 20x, 855y 70w x 25h 300
The weather <bin>/weather.rb -d | fmt -w 40 Helvetica, Regular, 10point 90x, 855y 210w x 38h 300
When the weather was updated <bin>/weather.rb -w Helvetica, Regular, 8point 35x, 878y 64w x 25h 300

The <bin> in the weather commands is the full path to the directory where you place the weather.rb script. That script is written in Ruby and calls the Weather Underground for the weather information. It needs to be modified so it's location matches yours. You can download the script from here.

Download the script and replace <your-state> with your two character state, e.g., PA. Replace <your-city> with your Weather Underground recognized city, e.g., West_Chester. You'll have to play with the Weather Underground site to find your city name. Save the altered script to your bin directory, e.g., /Users//bin. If you don't have a bin directory, create one. Make the script executable by typing 'chmod +x /Users/bin/weather.rb'. Test the script by running it - '/Users//bin/weather.rb -d'. Once you have it working, you can use it in Geek Tools.

#!/usr/bin/ruby
require 'rss/2.0'
require 'open-uri'
require 'optparse'
require 'fileutils'
 
summary = false
forecast = false
temperature = false
today = false
weatherdate = false
 
opts = OptionParser.new
opts.on("-s") { |val| summary = true }
opts.on("-f") { |val| forecast = true }
opts.on("-t") { |val| temperature = true }
opts.on("-d") { |val| today = true }
opts.on("-w") { |val| weatherdate = true }
opts.parse!
 
# Check if another process is downloading the weather and block until it's done
while File.file?('/tmp/weather.rb.tmp.lck')
  sleep(0.1)
end
 
# Download the weather if it's out of date
if !File.file?("/tmp/weather.rb.tmp") || ((Time.now - File.mtime("/tmp/weather.rb.tmp")) &gt; 1800)
  FileUtils.touch('/tmp/weather.rb.tmp.lck')
  `curl --silent -m 30 "http://rss.wunderground.com/auto/rss_full//.xml?units=english" &gt; /tmp/weather.rb.tmp`
  if File.size("/tmp/weather.rb.tmp") == 0
    FileUtils.rm("/tmp/weather.rb.tmp")
  end
  FileUtils.rm('/tmp/weather.rb.tmp.lck')
end
 
# Parse out the weather results
File.open('/tmp/weather.rb.tmp') do |f|
  response = f.read
  result = RSS::Parser.parse(response, false)
  result.items.each_with_index do |item, i|
    puts "#{item.title.gsub(/ - .*/, '')}"  if summary == true and i == 0
    puts "#{item.description.strip}nn" if forecast == true and i &gt; 0
    puts "#{item.title.gsub(/Current Conditions : /, '').gsub(/,.*/, '')}" if temperature == true and i == 0
    puts "#{item.description.gsub(/Today - /,'').gsub(/Tonight - /,'').gsub(/This Afternoon - /,'').gsub(/[rnt]/, '')}" if today == true and i == 1
    hour = item.pubDate.hour()
    if hour &lt; 12
      ampm = "AM"
    else
      ampm = "PM"
    end
    if hour == 0
      hour = 12
    end
    if hour &gt; 12
      hour = hour - 12
    end
    puts "#{item.pubDate.mon()}/#{item.pubDate.day()} #{hour}:#{'%02d' % item.pubDate.min()} #{ampm}" if weatherdate == true and i == 0
  end
end

Again, the URL "http://rss.wunderground.com/auto/rss_full/<your-state>/<your-city>.xml?units=english" portion of the script will need to be modified to match your location. Test the URL in your browser to find the right one for your version of the script.

The weather script stores the information it pulls down for 30 minutes (1800 seconds). Defined on this line:

if !File.file?("/tmp/weather.rb.tmp") || ((Time.now - File.mtime("/tmp/weather.rb.tmp")) &gt; 1800)

The delay is necessary to keep from pulling the information down repeatedly for each element in the display. You don't need to change this unless you want the delay to be different.

Update: I've posted about a new version of the weather script.


  1. There are some limits to Geek Tool formatting. You'll notice that the weather font looks a little ragged. The only way to get Geek Tool to blend text is to give it a shadow. But a shadow on such a small font looks terrible.


Share and Enjoy:
  • email
  • Twitter
  • Facebook
  • Slashdot
  • LinkedIn
  • Digg
  • DZone
  • Reddit

You might also enjoy

  1. Compiling Ruby with MacRuby 0.5b1
  • Hey Ted, thanks for the response.

    Hmmm. I run these in Terminal and it sort if sits there. I go to quit terminal and it gives me message:

    Closing this window will terminate the running processes: login, ruby, bash

    It's been running for more than 10 minutes.

    Any ideas?

    - Bartley
  • Since you saved the script to /Users/bartwilson/bin/weather.rb, then you use the chmod +x /Users/bartwilson/bin/weather.rb to make it executable. If you're unsure whether you've done it correctly try running the script using 'ruby /Users/bartwilson/bin/weather.rb'.
  • Hey Ted,

    I have got all of GeekTools, time, date running except Weather. I Used the Mac Text edit and saved the Wunderground script with NM and Santa_Fe as the city. Tested url, and I got Weather in Safari.

    Here's my script below saved in Users/bartwilson/bin/weather.rb

    .............................

    #!/usr/bin/ruby
    require 'rss/2.0'
    require 'open-uri'
    require 'optparse'
    require 'fileutils'

    summary = false
    forecast = false
    temperature = false
    today = false
    weatherdate = false

    opts = OptionParser.new
    opts.on("-s") { |val| summary = true }
    opts.on("-f") { |val| forecast = true }
    opts.on("-t") { |val| temperature = true }
    opts.on("-d") { |val| today = true }
    opts.on("-w") { |val| weatherdate = true }
    opts.parse!

    # Check if another process is downloading the weather and block until it's done
    while File.file?('/tmp/weather.rb.tmp.lck')
    sleep(0.1)
    end

    # Download the weather if it's out of date
    if !File.file?("/tmp/weather.rb.tmp") || ((Time.now - File.mtime("/tmp/weather.rb.tmp")) > 1800)
    FileUtils.touch('/tmp/weather.rb.tmp.lck')
    `curl --silent -m 30 "http://rss.wunderground.com/auto/rss_full/NM/Santa-Fe.xml?units=english" > /tmp/weather.rb.tmp`
    if File.size("/tmp/weather.rb.tmp") == 0
    FileUtils.rm("/tmp/weather.rb.tmp")
    end
    FileUtils.rm('/tmp/weather.rb.tmp.lck')
    end

    # Parse out the weather results
    File.open('/tmp/weather.rb.tmp') do |f|
    response = f.read
    result = RSS::Parser.parse(response, false)
    result.items.each_with_index do |item, i|
    puts "#{item.title.gsub(/ - .*/, '')}" if summary == true and i == 0
    puts "#{item.description.strip}\n\n" if forecast == true and i > 0
    puts "#{item.title.gsub(/Current Conditions : /, '').gsub(/,.*/, '')}" if temperature == true and i == 0
    puts "#{item.description.gsub(/Today - /,'').gsub(/Tonight - /,'').gsub(/This Afternoon - /,'').gsub(/[\r\n\t]/, '')}" if today == true and i == 1
    hour = item.pubDate.hour()
    if hour < 12
    ampm = "AM"
    else
    ampm = "PM"
    end
    if hour == 0
    hour = 12
    end
    if hour > 12
    hour = hour - 12
    end
    puts "#{item.pubDate.mon()}/#{item.pubDate.day()} #{hour}:#{'%02d' % item.pubDate.min()} #{ampm}" if weatherdate == true and i == 0
    end
    end

    ,,,,

    In Geek tool, I have two separate Shell commands. one for TEMP and the other for Weather forecast:

    /weather.rb -t

    /weather.rb -d | fmt -w 40

    I go to Terminal and I run the command:

    chmod +x /Users/bin/weather.rb

    or is it supposed to be:

    chmod +x /Users/bartwilson/bin/weather.rb

    I've done both and then in Terminal I run the test:

    /Users//bin/weather.rb -d

    and I've run

    /Users/bartwilson/bin/weather.rb -d

    I get nothing back. The Terminal just sits there and remains blank. I should get bartwilson$ as a return, but nothing happens.

    Any clue?

    -- Bartley
  • I've scoured the web for good scripts for Geektool. Your post goes way beyond the rest in providing the kind of detail I needed to get up and running.

    Care to do a follow up post on any other useful scripts?
  • yetiboy
    I'm having the same problem as the others, I get the undefined method 'hour' problem. I initially had a problem with only getting my city name up in the temperature position with the other two staying blank, but I thought it might be because I was using a Canadian city. When I tested out a US city, the old info stays in the tmp file and I get the undefined method error. Any ideas?
  • ed
    ctwise thanks for your help, but i cannot find this file anywhere. there is a tmp folder in my home folder in a folder named private but this weather.rb.tmp file doesnt exist there or anywhere else. what can i do to get this darn thing to work. thanks.
  • You can find the temp file in the /tmp directory in the file weather.rb.tmp.
  • ed
    this is the city and state information that i have in my weather file. it gives me the right info when i put it into safari. where can i fide the tmp file.

    http://rss.wunderground.com/auto/rss_full/CA/Ma...
  • The undefined method 'hour' for nil:NilClass probably indicates a problem downloading the weather information. Look at the file '/tmp/weather.rb.tmp' and see if it is non-blank and looks like it contains XML data.

    Try playing with the URL 'http://rss.wunderground.com/auto/rss_full//.xml?units=english' in your browser. Don't forget to insert your state and city in the URL.
  • ed
    im getting the same error as garren.
  • Garren DiPasquale
    undefined method 'hour' ?

    /Users/garren/bin/weather.rb:45: undefined method `hour' for nil:NilClass (NoMethodError)
    from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/time.rb:184:in `each_with_index'
    from /Users/garren/bin/weather.rb:40:in `each'
    from /Users/garren/bin/weather.rb:40:in `each_with_index'
    from /Users/garren/bin/weather.rb:40
    from /Users/garren/bin/weather.rb:37:in `open'
    from /Users/garren/bin/weather.rb:37

    Not sure what I'm doing wrong.
  • When you run this command 'chmod +x /Users/<your user="user" name="name">/bin/weather.rb', substituting your username, the command should just return. You can validate that it worked with the ls command, e.g., 'ls -l /Users/</your><your user="user" name="name">/bin/weather.rb'. It should show something like '-rwxr-xr-x@'. The x's indicate that the script is executable.

    When you run the script, pass a command line option, like '-d'. You should get output or an error message.</your>
  • Sean
    So when I put the chmod +x command in terminal it just goes to the next line, and then when I try to run it, i don't get any output at all. Whats going on?
  • whorider
    Never mind, Ted, I got. Thanks for your help (and patience)
  • whorider
  • whorider
    Having a little trouble as well, here's my output:

    tavs-macbook:~ tav$ /Users//bin/weather.rb -d
    /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rss/rexmlparser.rb:24:in `_parse': This is not well formed XML (RSS::NotWellFormedError)
    Missing end tag for 'HR' (got "BODY")
    Line:
    Position:
    Last 80 unconsumed characters:
    from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rss/parser.rb:163:in `parse'
    from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/rss/parser.rb:78:in `parse'
    from /Users//bin/weather.rb:39
    from /Users//bin/weather.rb:37:in `open'
    from /Users//bin/weather.rb:37
  • Most likely the location you're using in the script is invalid. Try entering the URL in a web browser and seeing what you get back. If you didn't edit the script then the URL is definitely bad: "http://rss.wunderground.com/auto/rss_full/<your-state>/<your-city>.xml?units=english"

    You need to replace "" and "", e.g, "http://rss.wunderground.com/auto/rss_full/PA/West_Chester.xml?units=english".
  • Adam
    I am having troubles.

    here is the output I am getting, many thanks

    dams-mbp:~ Adam$ /Users/Adam/Documents/weather.rb -d
    /Users/Adam/Documents/weather.rb: line 1: {rtf1ansiansicpg1252cocoartf949cocoasubrtf430: command not found
    /Users/Adam/Documents/weather.rb: line 2: {fonttblf0fmodernfcharset0: command not found
    /Users/Adam/Documents/weather.rb: line 2: f1fmodernfcharset0: command not found
    /Users/Adam/Documents/weather.rb: line 2: f2fmodernfcharset0: command not found
    /Users/Adam/Documents/weather.rb: line 3: syntax error near unexpected token `}'
    /Users/Adam/Documents/weather.rb: line 3: `}'
    adams-mbp:~ Adam$
  • It looks like you saved the script as an RTF (Rich Text Format) file. Try downloading it from here instead.
  • CrimsonCrow
    What!? I am not following this at all. I have several GeekTool Shell commands running: I have the date, IP address, iTunes, and a few others but I can not make sense of this one. Step by step for dummies? Please.

    Thanks.
  • I added some additional text and provided a downloadable copy of the script. Hopefully that will help.
  • Tim
    I am confused with the weather shell command where does the rest of the script go? an example?
  • Sure, copy the Ruby source code into a file named weather.rb. I saved mine in my personal bin (binaries) directory, e.g., /Users/tedwise/bin/weather.rb. I'm not sure if it's strictly necessary but you can then set it to be executable from Terminal.app with 'chmod +x /Users/tedwise/bin/weather.rb'.

    From that point you can run the weather.rb script from the command line to test it, e.g., '/Users/tedwise/bin/weather.rb -d'. The script is a little rough, I just hacked it together to support outputting weather on my desktop.
blog comments powered by Disqus