processi

about processes and engines

ruby, twitter, growl

update : added icons to script

I know, I know, others have already done it, and you’re probably using a Twitter client that does it : piping the tweets to Growl.

Anyway, I wanted to get rid of my current Twitter client (1 window less) and get incoming tweets via Growl while ‘posting’ tweets via my Twitter home page.

So I started looking for a Ruby – Growl bridge and, as I’m a user of the fine LimeChat, I went straight to GrowlNotifier which is a spin off of the growl notification found in LimeChat.

GrowlNotifier is available as a gem, but, like LimeChat, requires RubyCocoa, then it’s just

sudo gem install --no-ri --no-rdoc \
  rufus-verbs rufus-lru json_pure growlnotifier

(you can go for ‘json’ instead of ‘json_pure’ if you can)

and the script goes like :

require 'rubygems'

require 'rufus/verbs' # gem rufus-verbs
require 'rufus/lru' # gem rufus-lru
require 'json' # gem json or json_pure
require 'growl' # gem growlnotifier (and rubycocoa)

USER = ENV['TWUSER']
PASS = ENV['TWPASS']

raise 'TWUSER and/or TWPASS not set' \
  if (not USER) or (not PASS)

GROWL = Growl::Notifier.sharedInstance
GROWL.register(
  'twatch', ['twitter_update', 'issue'])

SEEN = LruHash.new(100) # max hash size

def fetch_tweets

  res = Rufus::Verbs.get(
    "https://twitter.com"+
    "/statuses/friends_timeline.json",
    :hba => [ USER, PASS ])

  raise "#{res.code} != 200" \
    if res.code.to_i != 200

  o = JSON.parse(res.body)

  o.each do |message|

    id = message['id']
    next if SEEN[id]

    user = message['user']
    u = user['profile_image_url']
    u = OSX::NSURL.alloc.initWithString(u)
    i = OSX::NSImage.alloc.initWithContentsOfURL(u)

    GROWL.notify(
      'twitter_update',
      "#{user['name']} (#{user['screen_name']})",
      message['text'],
      :icon => i)

    SEEN[id] = true
  end
end

loop do

  begin
    fetch_tweets
  rescue Exception => e
    p e
    GROWL.notify('issue', 'twatch issue', e.to_s)
  end

  sleep 45 # seconds
end

Next steps :

– clickable notifications for replies
– …

Written by John Mettraux

November 4, 2008 at 1:34 am

Posted in ruby, rufus, twitter

6 Responses

Subscribe to comments with RSS.

  1. This is great, thanks. However since I don’t like to have the process just take 15M of RAM all day I updated the script so it will exit after each run and added it to launchd. To store the state of the program I used memcached (sudo port install memcached && sudo gem install memcache-client). And because I don’t want to store the plain password on disk I used KeyChain to retrieve it. Attached is a diff from your script:

    0a1
    > #!/usr/bin/env ruby
    6a8
    > require ‘memcache’
    8,9c10,20
    < USER = ENV[‘TWUSER’]
    def get_password key
    > result = `/usr/bin/security 2>&1 >/dev/null find-internet-password -gs #{key}`
    > if result =~ /password: “(.*)”/
    > $1
    > else
    > raise “Unknown password”
    > end
    > end
    >
    > USER = ENV[‘TWUSER’]
    > PASS = get_password “twitter.com”
    18c29,31
    # SEEN = LruHash.new(100) # max hash size
    > CACHE = MemCache.new ‘localhost:11211’, :namespace => ‘twitter’
    > SEEN = (CACHE[‘seen’] || LruHash.new(100))
    52,61c65,69
    < loop do
    <
    < begin
    < fetch_tweets
    e
    < p e
    < GROWL.notify(‘issue’, ‘twatch issue’, e.to_s)
    < end
    <
    begin
    > fetch_tweets
    > rescue Exception => e
    > p e
    > GROWL.notify(‘issue’, ‘twatch issue’, e.to_s)
    62a71,72
    >
    > CACHE[‘seen’] = SEEN

    The .plist file to launch

    Label
    com.gpetrica.twitter
    Program
    /usr/local/bin/twitter.rb
    LowPriorityIO

    Nice
    10
    StartInterval
    60
    LimitLoadToSessionType
    Aqua

    If you want files please let me know.

    gpetrica

    January 30, 2009 at 11:11 am

  2. Hello,

    thanks a lot, it’s very nice, I don’t have a memcache server around but the get_password/launchd leverage are great.

    If you’d like to paste your files somewhere, I’d recommend http://gist.github.com

    An example : http://gist.github.com/54409

    You can post anonymously.

    Best regards, thanks again,

    John Mettraux

    January 30, 2009 at 12:25 pm

  3. So, I too didn’t want the script sitting around running, but rather on a 10 minute cron job, like my facebook growl updates.

    So, a modified version that saves state to disk and quits:

    http://pastie.org/426077

    Disk serializing thanks to: http://marcuswestinblog.blogspot.com/2008/03/save-ruby-objects-to-disk-for-later.html

    I’m a python hacker, not somuch with the ruby. Apologies for gross negligence.

    Steven Skoczen

    March 25, 2009 at 12:26 am

  4. Hi Steven,

    very nice, thanks for sharing !

    John Mettraux

    March 25, 2009 at 12:29 am

  5. Just wanted to thank you for posting this — I was able to modify it into a highly useful little script that uses Prowl to push notifications about @replies to my iPhone. :)

    David Edmiston

    September 15, 2009 at 12:57 am


Comments are closed.

%d bloggers like this: