Skip to content

Instantly share code, notes, and snippets.

@muffinista
Created April 25, 2011 23:51
Show Gist options
  • Save muffinista/941495 to your computer and use it in GitHub Desktop.
Save muffinista/941495 to your computer and use it in GitHub Desktop.
#!/bin/ruby
require 'skeleton'
class BuyThatBot < Skeleton
def search
debug "check for tweets since #{@config[:since_id]}"
#
# search twitter
#
search = @client.search('robocop', {:lang => "en"}.merge(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
exclude = ['soulja', 'crank', 'kraus', 'kanye', 'west', '808', "want no", "become", "movin", "mix", "@robocop"]
#blocklist = ['CollectiveDrone', 'Exclusionzone', 'Hyperborea47', 'IanDavidB']
search["results"].each { |s|
begin
skip_me = exclude.detect { |e| s["text"].downcase.include?(e) } != nil
if ! skip_me and ! on_blacklist?(s)
debug s["text"]
txt = "@#{s['from_user']} I'd buy that for a dollar!"
tweet txt, {:in_reply_to_status_id => s["id"]}, s
end
rescue Exception => e
puts e.inspect
debug e.message
end
}
end
end
end
@sk = BuyThatBot.new
@sk.run
#!/usr/bin/ruby
require 'rubygems'
require 'sequel'
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
attr_accessor :exclude
attr_accessor :blacklist
attr_accessor :debug_mode
attr_accessor :write_config
def skip_me?(s)
@exclude.detect { |e| s["text"].downcase.include?(e) } != nil
end
def on_blacklist?(s)
@blacklist ||= []
@global_blacklist ||= []
(@blacklist + @global_blacklist).detect { |b| s['from_user'].downcase.include?(b.downcase) } != nil
end
def debug_mode=(d)
@debug_mode = d
end
def debug_mode
return true if ENV['DEBUG'] == "true"
@debug_mode.nil? ? false : @debug_mode
end
def debug(s)
puts "***** #{s}"
end
def botname
self.class.to_s.downcase
end
def log(txt, source=nil)
# create a dataset from the items table
return unless @config.has_key?(:log_uri)
if @db.nil?
# connect to an in-memory database
@db = Sequel.connect(@config[:log_uri])
# # create an items table
if ! @db.tables.include?(:tweets)
@db.create_table :tweets do
primary_key :id
String :txt
String :bot
String :user
String :source_id
String :source_tweet
DateTime :created_at
end
end
end
tweets = @db[:tweets]
data = {:txt => txt, :bot => botname, :created_at => 'NOW()'.lit}
if source != nil
data = data.merge(:user => source['from_user'],
:source_id => source['id'],
:source_tweet => source['text'])
end
# populate the table
tweets.insert(data)
end
def load_global_blacklist
return unless @config.has_key?(:log_uri)
if @db.nil?
# connect to an in-memory database
@db = Sequel.connect(@config[:log_uri])
# # create an items table
if ! @db.tables.include?(:blacklist)
@db.create_table :blacklist do
String :user, :primary_key => true
DateTime :created_at
end
end
end
blacklist = @db[:blacklist]
@global_blacklist = blacklist.collect{|x| x[:user]}
end
def run
load_config
load_global_blacklist
login
begin
replies
search
other
rescue Exception => e
debug e.inspect
puts e.inspect
end
update_config
end
def other
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 = {}, original = nil)
debug txt
log txt, original
if debug_mode == false
@client.update txt, params
end
end
# track the most recent msg we've handled
def update_since_id(s)
if s.class != Bignum && s.class != Fixnum && s.class != String
if s.respond_to?("[]")
s = s["id"]
end
end
s = s.to_i
@tmp_since_id ||= @config[:since_id]
if @tmp_since_id.nil? or s > @tmp_since_id
@tmp_since_id = s
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:
# http://dev.twitter.com/apps/207151
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
if ! @tmp_since_id.nil?
tmp[:since_id] = @tmp_since_id
end
File.open(config_file, 'w') { |f| YAML.dump(tmp, f) } unless @write_config == false
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment