Twitter Bots, now with OAuth Goodness

The one devoted reader of this blog (Googlebot, I'm looking at you) probably remembers that I have a couple of bots running on Twitter. Originally I was using a library called Twibot, which was nice, but never quite worked the way I wanted it to. So eventually, I ended up with my own very simple code. I just finally updated my bots to authenticate via OAuth, a couple days before the deadline. While I was at it, I refactored most of the code into its own class, which the bots extend to add actual functionality. Here's the base class, which I call 'Skeleton' require 'rubygems' require 'twitter_oauth' require 'yaml' # # extend Hash class to turn keys into symbols # class Hash def symbolize_keys! replace(inject({}) do |hash,(key,value)| hash[key.to_sym] = value.is_a?(Hash) ? value.symbolize_keys! : value hash end) end end # # base class to handle being a twitter bot # class Skeleton attr_accessor :config attr_accessor :client def debug(s) puts "***** #{s}" end def run load_config login search replies update_config end def default_opts { :since_id => @config.has_key?(:since_id) ? @config[:since_id] : 0 } end # implement search in the extended class def search end # implement replies in the extended class def replies end # simple wrapper for sending a message def tweet(txt, params = {}) debug txt @client.update txt, params end # track the most recent msg we've handled def update_since_id(s) if @config[:since_id].nil? or s["id"] > @config[:since_id] @config[:since_id] = s["id"] end end protected # # handle oauth for this request. if the client isn't authorized, print # out the auth URL and get a pin code back from the user # def login @client = TwitterOAuth::Client.new( :consumer_key => @config[:consumer_key], :consumer_secret => @config[:consumer_secret], :token => @config[:token].nil? ? nil : @config[:token], :secret => @config[:secret].nil? ? nil : @config[:secret] ) if @config[:token].nil? request_token = @client.request_token puts "#{request_token.authorize_url}\n" puts "Paste your PIN and hit enter when you have completed authorization." pin = STDIN.readline.chomp access_token = @client.authorize( request_token.token, request_token.secret, :oauth_verifier => pin ) if @client.authorized? @config[:token] = access_token.token @config[:secret] = access_token.secret update_config else debug "OOPS" exit end end end # # figure out what config file to load # def config_file filename = "#{File.basename($0,".rb")}.yml" debug "load config: #{filename}" File.expand_path(filename) end def load_config tmp = {} begin File.open( config_file ) { |yf| tmp = YAML::load( yf ) } tmp.symbolize_keys! if tmp rescue Exception => err debug err.message tmp = { :since_id => 0 } end # defaults for now, obviously a big hack. this is for botly, at <a href="http://dev.twitter.com/apps/207151">http://dev.twitter.com/apps/207151</a> if ! tmp.has_key?(:consumer_key) tmp[:consumer_key] = "hjaOOEeeMpJSqZR7dvhxjg" tmp[:consumer_secret] = "wA5iqjfCf9aeGMMItqd6ylEEZAbcm7m6R7vVpaQV0s" end @config = tmp end # write out our config file def update_config(tmp=@config) # update datastore File.open(config_file, 'w') { |f| YAML.dump(tmp, f) } end end And here's the actual code for my newest bot @dr_rumack: #!/usr/bin/ruby require 'skeleton' class Surely < Skeleton def search debug "check for tweets since #{@config[:since_id]}" # # search twitter # search = @client.search('surely you must be joking', default_opts) if search != nil if @config[:since_id].nil? or search["max_id"].to_i > @config[:since_id] @config[:since_id] = search["max_id"].to_i end search["results"].each { |s| begin debug s["text"] txt = "@#{s['from_user']} I am serious, and don't call me Shirley!" tweet txt, :in_reply_to_status_id => s["id"] rescue Exception => e end } end end end @sk = Surely.new @sk.run Feel free to adapt this code in any way. I'd love to hear of any uses of it. I've thought about making it work more like twibot at some point, if there's any interest.

Tags: 

Add new comment