Fork: Twitterのタイムラインを監視してキーワードにマッチしたらGrowlするRubyスクリプト

Twitterのタイムラインを監視してキーワードにマッチしたらGrowlするRubyスクリプト - 今日覚えたことが面白そうだったので、参考にして書いてみた。

機能

  • タイムラインを見てターミナルに表示
  • キーワードを設定して、キーワードにマッチしたつぶやきをGrowl で通知

使い方

username: twitter のID
password: twitter のパスワード
interval: 更新頻度(秒)
keywords:
  - チェックしたいキーワード1
  - チェックしたいキーワード2
  ...
  - チェックしたいキーワードN


  • twittertail.yml.example
username: lukesilvia
password: hogehoge
interval: 60
keywords:
  - fuga
  - ほげ
  • 2.起動
$ ruby twittertail.rb
  • 3.終了

Ctrl-C


ソース

  • キーワードにマッチしたつぶやきはansi color 形式でハイライト
  • Growl の通知にはgrowlnotify を使っている
    • Growl のアイコンをtwitter のアイコンにするため
    • 要growlnotify
      • growlnotify でなくても、meow というgem をつかうとできるっぽい
  • イコン画像を出す
  • シングルトンクラス状態なのが微妙かも
    • Mechanize とかもnew することを考えると、これはこれでいいのかな
  • get_usericon がTwitterTail にあるのはちと微妙
    • モジュールつくってtwitter gem を拡張するとか?
# -*- coding: utf-8 -*-
# original: http://d.hatena.ne.jp/nacookan/20081022/1224698029

require 'rubygems'
require 'twitter'
require 'yaml'
require 'cgi'
require 'open-uri'

$KCODE = 'UTF8'

class TwitterTail
  class ConfigurationError < StandardError; end

  def initialize
    @config = load_config
    @twitter = Twitter::Base.new(@config['username'], @config['password'])
  end  

  def run
    begin
      loop do      
        read_timeline
        sleep @config['interval']
      end
    rescue Interrupt
      out("\n#{$0} Exit.")
    end
  end

  private
  
  def read_timeline
    @list ||= []
    cache_size = 100
    timeline = @twitter.timeline(:friends).reverse

    begin
      timeline.each do |status|
        next if @list.include?(status.id)
        @list << status.id
        
        user = status.user
        screen_name = user.screen_name
        text = CGI.unescapeHTML(status.text)
        
        if [screen_name, text].any?{|attr| Regexp.union(@config['keywords']).match(attr)}        
          out(screen_name, text, :highlight_with => @config['keywords'])          
          icon = get_usericon(screen_name, user.profile_image_url)
          notify(screen_name, text, icon)
        else
          out(screen_name, text)
        end          
      end

      @list = @list.last(cache_size)
    rescue Twitter::RateExceeded, Twitter::CantConnect, Twitter::Unavailable => e
      out(e.inspect)
    end
  end
  
  def load_config
    conf = YAML.load(File.read('twittertail.yml'))
      
    if conf['interval'] < 10
      raise ConfigurationError, 'interval must be more than 10 seconds.'
    else
      conf
    end       
  end

  def highlight(keys, *str)
    regexp = Regexp.union(Array(keys))
    
    str.map do |s|
      s.gsub(regexp){|matched| "\033[36m#{matched}\033[37m"}
    end
  end

  def out(*args)
    if args.size == 1
      puts(args)
    else
      options = args.last.is_a?(Hash) ? args.pop : { }
      name, text = args
      
      if keys = options[:highlight_with]
        name, text = highlight(keys, name, text)
      end
      
      puts("#{name}:  #{text}")
    end
  end

  def notify(title, msg, img = nil)
    cmd = "growlnotify -n twittertail -m #{msg.inspect} #{title} -H localhost"
    cmd << " --image #{img}" if img
    system cmd
  end

  def get_usericon(screen_name, icon_url)
    cache_dir_path = File.dirname(__FILE__) + '/icons/'
    Dir.mkdir(cache_dir_path) unless File.exist?(cache_dir_path)    
    
    icon_path = cache_dir_path + screen_name + '.ico'
    cache_lifetime = 60 * 60 * 24
    
    if(!File.exist?(icon_path) || (File.mtime(icon_path) + cache_lifetime < Time.now))
      File.open(icon_path, 'w') do |f|
        open(icon_url){|data| f.write(data.read(1024 * 10))}
      end      
    end
    
    icon_path
  end
end

TwitterTail.new.run
参考