O'Reilly Hacks
oreilly.comO'Reilly NetworkSafari BookshelfConferences Sign In/My Account | View Cart   
Book List Learning Lab PDFs O'Reilly Gear Newsletters Press Room Jobs  


 
Buy the book!
Mac OS X Panther Hacks
By Rael Dornfest, James Duncan Davidson
June 2004
More Info

HACK
#20
Update iChat Status with Mac::Glue
Keep your many committed fans apprised of what you're doing at just this moment in time, as reflected in your iChat status
The Code
[Discuss (0) | Link to this hack]

For some reason, many people like to let other people know what they're doing. In the long tradition of JenniCam (http://www.google.com/search?q=jennicam) and now the blogging phenomenon, some people on the Internet like to update their web pages or instant messaging status with what they are doing, watching, listening to, or thinking about at any particular moment in time.

When iChat was first released, there was no easy way to update your status automatically; you had to do so manually. One intrepid programmer found a way to do automate this process via iChat's private framework; the result was iChatStatus , which included various AppleScripts people could use to display their currently playing iTunes track, frontmost application, the document they're currently editing, and more.

But later versions of iChat support Apple Events for setting the status, and that's where this hack comes in.

The Code

This Perl script uses Mac::Glue to get the current track information from iTunes, find the frontmost application, and tell iChat to update its status to reflect your current activity.

TIP

You'll need to have the Mac::Glue Perl module installed before this script will work.

Save the script as happening.pl, wherever you please:

#!/usr/bin/perl
# what's happening!

# you need to create glues for all apps you will script, of course:
# % sudo gluemac /Applications/iTunes.app
# % sudo gluemac /Applications/iChat.app

use strict;
use warnings;
no warnings 'utf8', 'uninitialized';

use Encode 'from_to';
use File::Spec::Functions;
use Mac::Apps::Launch
use Mac::Glue 1.15;
use Mac::Glue ':all';
use Mac::Files;

my($app, $state, $track, %props, $status, $message, %apps);

my $tmp = FindFolder(kUserDomain, kTemporaryFolderType, kCreateFolder);
my $file = catfile($tmp, 'mystatus');

my $sleep = 10;
my $timeout = 5;

while (1) {
    my $output = itunes( );
    my $front = frontmost( );

    if ($output) {
        $output = $front . '; ' . $output
            unless $front =~ /^.?iTunes$/;
    } else {
        $output = $front;
    }

    ichat($output);

    sleep $sleep;
}

sub itunes {
    my $itunes = get_app('iTunes') or return;

    $state ||= $itunes->prop('player state');
    return unless $state->get eq 'playing';

    $track ||= $itunes->prop('current track');
    %props = map { $_ => $track->prop($_) } qw(name artist)
        unless keys %props;

    my %info;
    for my $prop (keys %props) {
        $info{$prop} = $props{$prop}->get;
    }

    my $str = $info{artist}
        ? "$info{artist} - $info{name}"
        : "$info{name}";
    from_to($str, "MacRoman", "iso-8859-9");
    return $str = "\x{266C}$str";
}

sub ichat {
    my($output) = @_;

    my $ichat = get_app('iChat') or return;

    $status ||= $ichat->prop('status');
    return unless $status->get eq 'available';

    $message ||= $ichat->prop('status message');
    $message->set(to => $output);
}

sub frontmost {
    my $system = get_app('System Events') or return;
    $app ||= $system->prop(name => item => 1,
        application_process => whose(frontmost => equals => 1)
    );

    my $front = $app->get or return;

    my $output = "\x{261B}" . $front;
    return $output;
}

sub get_app {
    my($app) = @_;
    if (!$apps{$app}) {
        eval { $apps{$app} = new Mac::Glue $app };
        if ($@) {
            $apps{$app} = 'NA'; # cache the failure
        }
        # set timeout for failure
        $apps{$app}->TIMEOUT($timeout);
    }

    # tried and failed
    if ($apps{$app} ne 'NA' && IsRunning($apps{$app}->{ID})) {
        return $apps{$app};
    } else {
        return;
    }
}

__END__

The script runs in a loop. The itunes() function checks to see whether iTunes is running and playing anything; if so, the script retrieves the name and artist of the current track and converts it into a string. A musical note ("\x{266C}" in Unicode) is added to the beginning of the string for giggles.

The frontmost application is discovered similarly; the frontmost() routine causes the background application System Events to return the name of the frontmost application, prepending it with a Unicode pointing hand ("\x{261B}").

Back in the main loop, the frontmost application name and current track (if any) are concatenated into one string, which in turn is sent to ichat(), where it is set as the value of the status message.

The main loop then sleeps for 10 seconds before starting all over again.

TIP

A larger version of this hack, with a lot more features (including setting your user icon in iChat to the album cover of the song you're listening to in iTunes), is available at http://dev.macperl.org/files/scripts/happening.


O'Reilly Home | Privacy Policy

© 2007 O'Reilly Media, Inc.
Website: | Customer Service: | Book issues:

All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.