Login
Home
Eoin Bailey . com
Tech, Research, Code, Work, and Fun
  • Home
  • Eoin's CV
  • About Eoin
  • Ph.D.
  • Blog
  • Galleries
  • Training
  • Polls
  • Tags
  • Weblinks
  • Site map
  • Contact

A Random Image

Guinness Widget

Tag Cloud

algorithm antarctica apple banking browser code copyright cycle data centre devel Dijkstra drupal drupalcamp economics escapades facebook firefox galway Google iphone ipod livigno theme training weights
more tags

GeekTool

Submitted by Eoin on Fri, 20/11/2009 - 15:42
in
  • apple
  • code
  • General-Personal
  • osx

GeekTool is my new favourite application on my mac. This little tool allows me to display information on my desktop. You can choose between shell scripts and images. I use it to display the following information:

  • Number of unread mails in Apple Mail
  • Number of unread mails in Gmail
  • Number of unread items in Vienna (RSS reader)
  • Time and date
  • Calendar for the current month
  • Hard disk space (both free and used)
  • Used RAM
  • CPU in use
  • A display that shows if all the websites I manage are up and running, and if not, which sites are down
  • Todays weather in image and short text form
  • Tomorrows weather in text form.

Here is an image of what it looks like:

GeekTool Setup Nov 2009GeekTool Setup Nov 2009

How did I do all this?

Well, I searched Google a lot, and found other people's scripts and shell commands for a good portion of this. But here are all the commands/scripts I use:

First off, all the titles, e.g, "Apple Mail", "Today", are just standard text, using this shell command

echo "Today";

I'll go left to right, and I should mention that this code could really do with some serious cleanup, but I have a lot of other things to do, and I left in a good number of methods that I would like to use in the future, but are currently commented out.

E-Mail/RSS

As I said above, the titles are just the 'echo' command, and I moved them to the positions they are in (that's all a drag and drop operation in Geektool, but you can use co-ordinates if you want).

The interesting part is the scripts. They are a hodge-podge of AppleScript (Apple Mail and Vienna) and Python (Gmail). I can't remember where I got all these, but if I do (or you recognise them, let me know and I'll add attribution).

Apple Mail Script

(for some reason my applescript Syntax Highlighter brush isn't working)

tell application "System Events" to set iCalIsRunning to (name of processes) contains "Mail"
set finalText to ""
if iCalIsRunning then
	tell application "Mail"
		set unreadCount to unread count of inbox
		if (unreadCount is greater than or equal to 2) then
			return (unreadCount as string) & " new messages"
		else if (unreadCount is equal to 1) then
			return (unreadCount as string) & " new message"
		else
			set finalText to "No new Mail"
		end if
	end tell
	
else
	set finalText to "Mail not open"
end if

The script will check if Apple Mail is open, if not, it outputs 'Mail Not Open', if it is open, it checks the Inbox for the number of unread messages, and also checks if it is a single unread message; I don't like having a (s) at the end of 'message', so if there is only one message 'message' is single, if not there is more than one message it adds the 's'.

Gmail

#!/usr/bin/env python
# encoding: utf-8

# Copyright (c) 2009 Greg Newman
# 
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
# 
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.

import os
import imaplib,re
import sys

def main(argv=None):
    i=imaplib.IMAP4_SSL('imap.gmail.com')
    try:
        i.login("username","password")
        x,y=i.status('INBOX','(MESSAGES UNSEEN)')
        messages=int(re.search('MESSAGES\s+(\d+)',y[0]).group(1))
        unseen=int(re.search('UNSEEN\s+(\d+)',y[0]).group(1))
        if unseen == 0:
        	print "No new mail"
        elif unseen == 1:
			print "1 new message"
        elif unseen > 1:
			print unseen, " new messages"
        else:
			print "Offline"
    except:
		print "Offline"

if __name__ == '__main__':
    sys.exit(main())

Because I am obsessive about my system displaying something nice, even when I'm not online, I modified the original script to print something when it can't connect to the Gmail servers.

Vienna (RSS feed reader)

tell application "System Events" to set viennaIsRunning to (name of processes) contains "Vienna"
set finalText to ""
if viennaIsRunning then
	tell application "Vienna"
		set unreadCount to total unread count
		if (unreadCount is greater than or equal to 2) then
			return (unreadCount as string) & " unread items"
		else if (unreadCount is equal to 1) then
			return (unreadCount as string) & " new messages"
		else
			set finalText to "No Unread Items"
		end if
	end tell
	
else
	set finalText to "Vienna not open"
end if

This is very similar to the Apple Mail script, again checking if Vienna is open before doing anything (if you don't do this step, it will open Vienna when the script is run).

Using these scripts

In Geektool, to use these scripts the following shell commands are used, you need to know where your scripts are stored also:

osascript ~eoinbailey/bin/mailUnreadCountGeekTool.scpt
/Users/eoinbailey/bin/gmail.py;
osascript ~eoinbailey/bin/ViennaUnreadCount.scpt

I set all these to refresh every 100 seconds.

Additionally you need to make sure that the scripts are executable (AppleScript doesn't need this I don't think). To make a script executable:

chmod a+x scriptname.py

Date/Calendar Info

I'm not going to go into the layout and the fonts/size, this will change depending on how you want it to look

Day of the Week

date +%A

Month of the Year

date +%B

Date of the month

date +%d

Time

date '+%I:%M'

AM/PM

date +%p

Calendar

cal

You need a fixed width font, such as monaco, for the calendar, otherwise it won't line up nicely, and look pretty.

System Information

For the system information section, I display the hard drive size, space used, and percentage used; allocated RAM; and CPU usage.

For hard disk space:

df -hl | grep 'disk0s2' | awk '{print "Biggie : " $4"/"$2" free ("$5" used)"}'

For RAM:

top -l 1 | awk '/PhysMem/ {print "RAM : " $8 " used "}'

For CPU:

top -l 2 | awk '/CPU usage/ && NR > 5 {print $1, ":", $3, $4, $5, $6, $7, $8}'

Websites Available

This is one of the sections I am most proud of. I have developed a number of websites, both for personal use, and for others. This section lets me know if these websites are available, and if they are not, it prints out the websites that are down, while also changing the icon red.

The script (this is modified from another script, I can't remember where I found the original script):

#!/usr/bin/perl
use Mail::Mailer;
use LWP::UserAgent;
use HTTP::Status;

# input variables
$url_fn     = "/Users/eoinbailey/bin/websitePing/mysites.txt";          # domain list file
$address_to = "bailey@example.com"; 							            # email address for which to send alerts

chomp($url_fn);
chomp($address_to);

# program variables
$exit_status = 0;		#status 0 - success, status 1 is failure.

# product information
$version       = '0.1';
$spidername    = 'websitePing v'.$version.' (Website Monitor)';  # Spider's Agent Name
$max_bytes     = 10; # limit content download to 10 bytes (we only need status code anyway)

# generate timestamp
@abbr = qw( JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC );
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
$timestamp = sprintf("%02d:%02d", $hour, $min);
$date      = sprintf("%02d-%s-%04d", $mday, $abbr[$mon], $year+1900);

# **************************************************************************
# read url/email list, create url/email array @urls
open (URL_LIST, $url_fn) or die 'Error: Cannot open list of URLs ('.$url_fn.'). ['.$!."]\n\n";

while ($url_ln = )
{
   $url_ln =~ s/ //g; # perl's str_replace eq., s/replace this/with this/g (g = globally)
   push(@urls, $url_ln);
}

chomp(@urls);
@urls = grep(!/^#/, @urls);  # remove comment lines
close (URL_LIST);

# **************************************************************************
# begin LWP::UserAgent object
my $ua = LWP::UserAgent->new;
$ua->agent($spidername);



# **************************************************************************
# Check if google.com is online. If it is not, assume I am offline!

$site_url = "http://google.com";
$response = $ua->head($site_url);
if ($response->code != RC_OK) {
	print "Computer is offline,\nto check websites please reconnect.";
	exit 0;
}



# **************************************************************************
 # open url, check status code & email alert if status changed
 for $url (@urls)
 {
    # ***********************************************************************
    # extract site url & email address from array
    ($site_url, $site_email) =  split(/,/, $url, 2);

    # read main page from website
    $response = $ua->head($site_url);

	# the status code for the url
	# status code info: http://www.xav.com/perl/site/lib/HTTP/Status.html
	#print $response->code;

	if ($response->code != RC_OK) {
		# we did not get a status '200' back.
		print $site_url;
		print "\n";
		$exit_status = 1;
	}


	# ***********************************************************************
	# email alert message ...
	# have to put in a conditional statement to only send an e-mail if it's a bad alert code.
	#$mailer = Mail::Mailer->new();
#
#	$address_from  = $site_email;
#	$subject       = $response->code.' '.status_message($response->code).' @ '.$timestamp;
#	$body          = 'url: '.$site_url."\n on: ".$date;
#	$importance    = 'normal';
#
#	if (is_error($response->code))
#	{
#		$importance = 'high';
#	}
#
#	$mailer->open( {From => $address_from, To => $address_to, Subject => $subject, Importance => $importance} ) or die 'Error: Cannot open email. ['.$!."]\n\n";
#
#	print $mailer $body;
#	$mailer->close();
	# ***********************************************************************

}


if ($exit_status == 0) {
	print "All Websites Running";
	rename("failure.png", "success.png");
} else {
	rename("success.png", "failure.png");
}

exit $exit_status;

The script assumes that if it can't access 'google.com' you are not online, and doesn't check the sites. If it accesses google, it reads in a text file, which for me looks like this:

http://eoinbailey.com,					bailey@example.com
http://pintmaps.com,					bailey@example.com
http://eleanoroneill.com, 				bailey@example.com
http://thespineclinic.ie, 				bailey@example.com
http://design21c.com,			 		bailey@example.com
http://medilex.ie, 					bailey@example.com
http://trace.ie, 					bailey@example.com
http://private.pintmaps.com, 			        bailey@example.com
http://careersandoutplacement.ie, 		        bailey@example.com

The e-mail address may be used in the future to send out an e-mail warning if a site is down. The e-mail address can be changed on a per site basis, but I don't use it yet, and most likely I would be the person who would want to know.

The script was also going to have an image, 'success.png', but I use the standard geektool icons instead, and change the exit status of the program instead. What this means is that if the script can reach all the sites, it exits with exit status '0' which represents success, if it failed to reach a site, it prints out the websites that were unreachable, and exits with status '1' which is a failure. To get the icon, enable it if GeekTool, under 'icon', and tick the 'enable icon' box. I just use the default icons, I like how they look.

To execute the script:

/Users/eoinbailey/bin/websitePing/websitePing.pl

Weather for Today

I load a local image... but how do I update that image I hear you say. Well, I have a script for that! It's a two step process. First off, I get Dublin's weather from yahoo, on this page:

http://weather.yahoo.com/ireland/dublin/dublin-560743/

I have a webpage that pulls down that page, and strips out everything except the image see:

http://eleanoroneill.com/weather_image.php

This looks like this:

<?php
/* Be Sure to replace CITYDATA in $url with your own city from Yahoo */

//$url="http://weather.yahoo.com/forecast/EIXX0014.html";

$url="http://weather.yahoo.com/ireland/dublin/dublin-560743/";

$ch = curl_init();
$timeout = 0; // set to zero for no timeout
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$file_contents = curl_exec($ch);
curl_close($ch);

$divStart = "

To make this work for your city, you need to change the URL for the yahoo weather page.

Then, to cache this image locally (so that I can still see a nice image even when offline :), I use this:

#!/usr/bin/perl
use URI::URL;
use LWP::UserAgent;
use HTTP::Status;

# Pull down the image from the website, and display it, or... display a message 
# about being offline

#http://eleanoroneill.com/weather_image.php

$spidername    = 'websiteWeather v0.1';  # Spider's Agent Name


# **************************************************************************
# begin LWP::UserAgent object
my $ua = LWP::UserAgent->new;
$ua->agent($spidername);

# **************************************************************************
# Check if google.com is online. If it is not, assume I am offline!

$site_url = "http://google.com";
$response = $ua->head($site_url);
if ($response->code != RC_OK) {
	print "Offline";
	# If offline, copy an image for offline use to 'current_weather.png'
	exit 1;
}

save_image("http://eleanoroneill.com/weather_image.php", "/Users/eoinbailey/bin/weather/current_weather.png");

#
#SAVE IMAGE------------------------------------------------------------------------------
#This script will grab an image from a web page and save it locally
#file - This is the name of the image on the server
#$download - This is where the image will be saved locally
#save_image($file, $download);
sub save_image { #copy web FILE to local DOWNLOAD location
	my ($file, $download) = @_;
 
	my $user_agent = LWP::UserAgent->new;
	my $request = HTTP::Request->new('GET', $file);
	my $response = $user_agent->request ($request, $download);
}

I don't do anything at the moment if it's offline, except display the last cached image. I might change that down the line.

To get the textual short version of today's weather, it's this line:

curl --silent "http://xml.weather.yahoo.com/forecastrss?p=EIXX0014&u=c" | grep -E '(Current Conditions:|C//' -e 's///' -e 's/<\/b>//' -e 's/
//' -e 's///' -e 's/<\/description>//'

Again, this will need to be updated for your locatiom. The "EIXX0014" part is the location for Dublin. I also pull the data down in Celsius, not Fahrenheit.

Weather for Tomorrow

To get tomorrow's weather, again, I use a script:

#!/usr/bin/perl
use URI::URL;
use LWP::UserAgent;
use HTTP::Status;

# Pull down the weather forecast from the url or else display a message that 
# says 'Offline'

#curl -s http://eleanoroneill.com/tomorrows_weather.php

$spidername    = 'websiteTomorrowsWeather v0.1';  # Spider's Agent Name


# **************************************************************************
# begin LWP::UserAgent object
my $ua = LWP::UserAgent->new;
$ua->agent($spidername);

# **************************************************************************
# Check if google.com is online. If it is not, assume I am offline!

$site_url = "http://google.com";
$response = $ua->head($site_url);
if ($response->code != RC_OK) {
	print "Offline";
	exit 1;
}

# **************************************************************************
# Download the text from the page, and print it.


$site_url = "http://eleanoroneill.com/tomorrows_weather.php";
$response = $ua->get($site_url);
if ($response->code != RC_OK) {
	print "Offline";
	exit 1;
} else {
	print $response->content;
	exit 0;
}

To execute this script:

/Users/eoinbailey/bin/weather/tomorrow_weather_forecast.pl;

The astute amongst you will see, that again I pull it down from a webpage that I have setup. I use that page to strip out everything but the little bit of text I want to use. The code for that webpage:

<?php
/* Be Sure to replace CITYDATA in $url with your own city from Yahoo */

//$url="http://weather.yahoo.com/forecast/EIXX0014.html?unit=c";

$url="http://weather.yahoo.com/ireland/dublin/dublin-560743/?unit=c";

$ch = curl_init();
$timeout = 0; // set to zero for no timeout
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$file_contents = curl_exec($ch);
curl_close($ch);

$divStart = "
  • Tomorrow:"; $start = strpos($file_contents, $divStart) + 30; $file_contents=substr($file_contents, $start); $strEnd = "
  • "; $end = strpos($file_contents, $strEnd); //$length = $end-$start; $tomorrows_weather=substr($file_contents, 0 , $end); print $tomorrows_weather; ?>

    If you want the weather for Dublin, you can use everything as I've listed here exactly to pull up your info.

    The last thing I should mention is that I have GeekTool create the black bar that all this goes on, so I can change my wallpaper easily without having to edit the image. To make the black bar I just create a new entry that has no command, but has a background colour (black in this example), and make that window the width of the screen, and in my example its 120 pixels high, which gives a nice visual on my screen.

    • Eoin's blog
    • Printer-friendly version
    • Send to friend

    Comments

    Post new comment

    The content of this field is kept private and will not be shown publicly.
    • Web page addresses and e-mail addresses turn into links automatically.
    • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
    • Lines and paragraphs break automatically.
    • Images can be added to this post.

    More information about formatting options

    Current Poll

    Who is your favourite scientist?:

    Freelance Work

    A sample of websites I have developed:

    • Studio Richards
    • Medilex
    • Design21C
    • The Spine Clinic
    • Abrivia - Careers and Outplacement
    • Emilie Conway

    Training

    • Spinning
    • Hodson Bay Hotel Training
    • Spinning Class - Not too Shabby!
    • Bike Time Trial
    • Spinning Class of Anti-Doom!

    Some Links

    • James Bond Opening Scenes
    • Polls
    • Chess Module-Drupal
    • Ski Trip Jan 2009

    Recent Comments

    • external controls via css classes instead of alternate text
    • What if there's more stuff
    • heheh good job man
    • Impressive confidence!
    • Honestly, you may think your
    • Maybe
    • SEO benefits
    • hey dat was nice
    • Time makes fools of us all.
    • I guess I'll have to update

    Powered by

    Powered by Drupal, an open source content management system

    Recent blog posts

    • Intellectual Property, Copyright and Free
    • What Sites are using Drupal?
    • Hit The Road - version 2
    • Richard Feynman - On The Relevancy of Science
    • Lines of Communication are [too] Open?
    • Dublin Web Summit - June 2010
    • Reading Software Licence Agreements
    • PhD, Engineering, Tech - Updates
    • O2 Contracts
    • DrupalWest - Drupal Refresh
    more
    Copyright © 2010 Eoin Bailey . com.