Tuesday, September 09, 2008

Campfire activity notifier for Gnome, KDE, or console

The 37signals blog points out a simply Ruby script for KDE that will give you a visual notification when a new message is posted to a Campfire chat room. I have modified that script to work for Gnome as well as KDE, and additionally a text console. I also made a few other additions such as:

  • Allow you to specify a specific chat room(s) as a command line argument
  • Multiple chats rooms can be monitored concurrently using threading
  • Added the Campfire logo to the notifications
  • Added some initial status messages to display login status, room topic, and current people in the room
  • Display of the last 3 messages of the current day's transcript so you know what's going on without need to login
  • Filter out ads
Here is my version of the script:
#!/usr/bin/env ruby

# == Synopsis
#      Program to monitor a campfire chat room
#      Modified from code provided at: http://www.snailbyte.com/2007/09/13/campfire-activity-notifier-for-kde/
#
# == Usage
#      campfireMonitor [roomName] [roomName] ...
#
# == Author
#      Steven Pothoven and Snailbyte Ltd.

require 'rubygems'
require 'tinder'
require "cgi"

class App
  VERSION = '0.1.1'

  def initialize arguments, stdin
    # default settings
    campfireSubdomain = 'mySubdomain'
    campfireUsername = 'user@email.com'
    campfirePassword = 'password'
    roomNames = ['Room1', 'Room2']
    if arguments.length > 0
      roomNames = arguments
    end

    @ui = 'gnome'
    @campfireIconPath = '/path/to/campfire-logo.png'
    # define you favorite audio player and audio file here for audio notifications
    @soundCommand = 'mplayer /usr/share/sounds/pop.wav'
  

    @campfire = Tinder::Campfire.new campfireSubdomain
    if @campfire.login campfireUsername, campfirePassword
      alert nil, "CampfireMonitor", "Successfully logged in #{campfireUsername}"
      @rooms = roomNames.collect { |roomName| @campfire.find_room_by_name roomName }
      # remove any invalid rooms
      @rooms.delete(nil);
      @rooms.each do |room|
        notify room, "CampfireMonitor", "Entered room."
        notify room, "CampfireMonitor", "Topic is: #{room.topic}.".gsub("'","")
        notify room, "CampfireMonitor", "Current users are:  #{room.users}.".gsub("'","")
      end
    else
      alert nil, "CampfireMonitor", "Failed to log in #{campfireUsername}"
    end
  end

  # display notifcation message
  def notify room, user, msg
    if msg and msg.size > 0
      msg = CGI.unescapeHTML(msg);
      if @ui == 'kde'
        system "dcop knotify default notify eventname \'#{user}\' \'#{''+@campfire.uri.to_s+'/room/'+room.id+'/'+room.name+': ' unless room.nil?} #{msg}\' '' '' 16 2"
      elsif @ui == 'gnome'
        system "notify-send -i #{@campfireIconPath} '#{user}' '#{''+@campfire.uri.to_s+'/room/'+room.id+'/'+room.name+': ' unless room.nil?} #{msg}'"
      else
        puts "#{room.name+':' unless room.nil?}#{user} - #{msg}"
      end
    end
  end
  
  # notify with sound
  def alert room, user, msg
    notify room, user, msg
    if @soundCommand and @soundCommand.length > 0
      system @soundCommand
    end
  end

  def run
    # first get any missed messages for today
    threads = []
    @rooms.each do |room|
      thread = Thread.new do
        room.transcript(Date.today).last(3).each do |m|
          if !m.nil? and m[:message] and m[:message].size > 1
            notify room, m[:person], m[:message].gsub("'","")
          end
        end
      end
      threads << thread
    end
    threads.each { |thread| thread.join}

    # listen for more messages
    threads = []
    @rooms.each do |room|
      thread = Thread.new do
        notify room, "CampfireMonitor", "Waiting for messages..."
        room.listen do |m|
          if !m.nil? and m[:message].size > 1
            unless m[:person] == "Ad"
              alert room, m[:person], m[:message].gsub("'","")
            end
          end
        end
      end
      threads << thread
    end
    threads.each { |thread| thread.join}

  end
end

app = App.new(ARGV, STDIN)
app.run
I'm sure you can think of plenty more customizations such as command-line options for all the default settings, etc. But I wanted to keep it fairly simple. One last thing, here is the cropped version of the Campfire logo I use for my notifications (campfire-logo.png):

2 comments:

Unknown said...

Just to save the next person 30 seconds: you may need to add the :ssl => true option to Tinder::Campfire.new. Also room names are room names, not numbers.

Unknown said...
This comment has been removed by the author.