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

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

A Random Image

http://StudioRichards.com

GeekTool

Submitted by Eoin on Fri, 20/11/2009 - 14: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

    Comment viewing options

    Select your preferred way to display the comments and click "Save settings" to activate your changes.

    Gmail Unread

    Submitted by michael (not verified) on Fri, 22/10/2010 - 06:51.

    How can I make the python file executable such that GeekTools can run it? I'm fairly new to GeekTools (and Terminal), so making files executable has been a hangup for me. Thanks for your help.

    • reply

    To make a file executable, in

    Submitted by Eoin on Fri, 22/10/2010 - 10:45.

    To make a file executable, in the terminal type in 'chmod a+x '

    You can also make a file executable in OS X by selecting the file, using the key combo 'CMD+i' which brings up the file info and then in the permissions section click on 'execute', select it for all groups. Upon double checking this might only be true in Path Finder, a Finder replacement App that I highly recommend!

    • reply

    Syntax Error

    Submitted by James (not verified) on Thu, 17/02/2011 - 10:26.

    Hi, there seems to be a syntax error in the site tracker Perl script. Running in terminal produces compilation errors. I suspect your cms may have screwed some characters. Error is on line 32 and 35.

    • reply

    Reading Vienna

    Submitted by Harry Wagendorp (not verified) on Fri, 01/04/2011 - 04:49.

    Get your unread vienna in stead of the number .....

    #!/usr/bin/osascript

    (* myFolder is the folder & subfolders you want the unread messages for the last amountOfHours hours *)

    set myFolder to "1 Mijn nieuws"
    set myCurrentDate to the (current date)
    set amountOfHours to 2
    set earlyCurrentDate to (myCurrentDate - amountOfHours * hours)
    set viennaNews to ""
    set readCounter to 0
    set theOutput to "
    "

    tell application "Vienna"
    refresh subscription for folder myFolder
    delay 2
    set counter to count of articles in folder myFolder
    if counter > 0 then
    repeat with i from 1 to counter
    set myViennaDate to date of article i of folder myFolder
    set myViennaRead to read of article i of folder myFolder
    --display dialog myViennaRead as text
    if (myViennaDate > earlyCurrentDate) and (not myViennaRead) then
    --if (myViennaDate > earlyCurrentDate) then
    set containingFolder to name of containing folder of article i of folder myFolder
    set theTitle to title of article i of folder myFolder as string
    set theBody to the body of article i of folder myFolder
    -- set viennaNews to theTitle & ": " & return & theBody & return & return & viennaNews
    -- set viennaNews to "• " & theTitle & ": " & return & viennaNews
    set viennaNews to "• " & containingFolder & ":" & theTitle & return & viennaNews
    copy readCounter + 1 to readCounter
    --display dialog i & ", " & theTitle
    end if
    end repeat
    end if
    if readCounter = 0 then
    set kop to " Geen ongelezen artikel in Vienna de afgelopen " & amountOfHours & " uur."
    else if readCounter = 1 then
    set kop to "" & readCounter & " artikel in Vienna de afgelopen " & amountOfHours & " uur."
    else if readCounter > 1 then
    set kop to "" & readCounter & " artikelen in Vienna de afgelopen " & amountOfHours & " uur."
    end if
    if viennaNews = "" then
    set viennaNews to "Geen nieuwe artikelen in Vienna afgelopen " & amountOfHours & " uur ."
    else if viennaNews ≠ "" then
    set viennaNews to kop & return & return & viennaNews
    end if
    set theOutput to viennaNews
    theOutput
    end tell

    • reply

    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

    What is your current phone OS?:

    Freelance Work

    A sample of websites I have developed:

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

    Twitter

    Follow @eoinbailey

    Some Links

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

    Training

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

    Recent Comments

    • Happy New Year 2012!
    • Thank you..
    • Simple way
    • Yep, CSS is an option - there
    • Maybe CSS is an easy solution?
    • Thanks for the direction.
    • Thank you for the insight.
    • Exactly.
    • Thank you for the insight.
    • I'm open to correction on

    Powered by

    Powered by Drupal, an open source content management system

    Recent blog posts

    • Leap Card
    • A new College term - Dijkstra's Algorithm
    • Dublin GTUG - June 2011 - Over 100 attendees
    • City of a Thousand Welcomes
    • Groupon et al. - "Bet on the Future"
    • Dublin Web Summit - DWS6 - Roundup
    • Anti-Spam - Using a Catch-All to identify bad companies
    • Hide a Note Title - Drupal 7
    • The Election on Hit The Road
    • Syntax Highlighter Module - Javascript Problem
    more
    Copyright © 2012 Eoin Bailey . com.

    I'm trying out: Web Analytics