Created
February 6, 2023 00:30
-
-
Save jnewland/f661c6b87c1d3f62413b382cd4d14dbd to your computer and use it in GitHub Desktop.
From May of 2008, for historical purposes: a Twitter bot that allowed sharing your location on Fire Eagle (RIP) via DMs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Tiny Twitter Bot. | |
# | |
require 'rubygems' | |
require 'xmpp4r-simple' | |
require 'active_record' | |
require 'fireeagle' | |
require 'kconv' | |
require 'shorturl' | |
require 'uri' | |
DEBUG = true | |
class Invite < ActiveRecord::Base | |
end | |
class User < ActiveRecord::Base | |
attr_accessor :fireeagle | |
def init_fireeagle(app_id, consumer_key, consumer_secret) | |
if self.authorized? | |
@fireeagle = FireEagle::Client.new( | |
:consumer_key => consumer_key, | |
:consumer_secret => consumer_secret, | |
:app_id => app_id, | |
:access_token => self.access_token, | |
:access_token_secret => self.access_token_secret) | |
elsif self.has_request_token? | |
@fireeagle = FireEagle::Client.new( | |
:consumer_key => consumer_key, | |
:consumer_secret => consumer_secret, | |
:app_id => app_id, | |
:request_token => self.request_token, | |
:request_token_secret => self.request_token_secret) | |
else | |
@fireeagle = FireEagle::Client.new( | |
:consumer_key => consumer_key, | |
:consumer_secret => consumer_secret, | |
:app_id => app_id) | |
end | |
end | |
def has_request_token? | |
!self.request_token.blank? && !self.request_token_secret.blank? | |
end | |
def authorized? | |
!self.access_token.blank? && !self.access_token_secret.blank? | |
end | |
def get_request_token | |
token = self.fireeagle.get_request_token(true) | |
self.update_attributes(:request_token => token.token, :request_token_secret => token.secret, :access_token => nil, :access_token_secret => nil) | |
return token.token | |
end | |
def authorization_url | |
return nil unless self.has_request_token? | |
self.fireeagle.authorization_url | |
end | |
def authorize | |
return false unless self.has_request_token? | |
begin | |
token = self.fireeagle.convert_to_access_token | |
self.update_attributes(:request_token => nil, :request_token_secret => nil, :access_token => token.token, :access_token_secret => token.secret) | |
return true | |
rescue | |
return false | |
end | |
end | |
def update_location(q) | |
return false unless self.authorized? | |
self.fireeagle.update(:q => q).success? | |
end | |
def location | |
return false unless self.authorized? | |
begin | |
response = self.fireeagle.user | |
return response.best_guess.name | |
rescue | |
return nil | |
end | |
end | |
def to_s | |
self.username | |
end | |
end | |
class DangerDay | |
attr_accessor :client, :app_id, :consumer_key, :consumer_secret, :num_checks, :user, :pass | |
def initialize(user, pass, app_id, consumer_key, consumer_secret) | |
Jabber::debug = ENV['DEBUG'] || false | |
@user, @pass = user, pass | |
jabber_login | |
@app_id = app_id | |
@consumer_key = consumer_key | |
@consumer_secret = consumer_secret | |
@num_checks = 0 | |
end | |
def jabber_login | |
@client = Jabber::Simple.new(@user, @pass) | |
end | |
def run | |
while (true) do | |
@num_checks += 1 | |
jabber_login if ((@num_checks % 1000) == 0) | |
sleep(10) | |
puts "checking for new messages..." if DEBUG | |
@client.received_messages do |message| | |
puts "Received: " + Time.now.to_s if DEBUG | |
puts message.from if DEBUG | |
puts message.body if DEBUG | |
puts "-"*80 if DEBUG | |
unless message.type == :error | |
if message.from == "twitter@twitter.com" | |
if message.body =~ /Direct from (.*):/ | |
sender = $1 | |
body = message.body.split(/\r?\n/)[1].strip | |
self.process_direct_message(sender, body) | |
# if direct | |
elsif message.body =~ /(.*): .* L:(.*)/ | |
sender = $1 | |
location = $2 | |
self.process_twittervision_update(sender, location) | |
end | |
elsif message.from == "jnewland@gmail.com" | |
if message.body =~ /ping/ | |
self.jabber_message("jnewland@gmail.com", "pong #{Time.now}") | |
end | |
end # if from twitter | |
end # unless error | |
end # callback | |
end | |
end | |
def process_twittervision_update(sender, location) | |
puts "Got a Twittervision-style update!" if DEBUG | |
#remove the label from the message if one is provided | |
loc_array = location.split("=") | |
location = loc_array[1] if loc_array.size > 1 | |
# find the user | |
user = User.find_by_username(sender) | |
if user | |
user.init_fireeagle(app_id, consumer_key, consumer_secret) | |
user.update_location(location) if user.authorized? | |
end | |
end | |
def process_direct_message(sender, body) | |
puts "Got a Direct Message!" if DEBUG | |
# find the user | |
user = User.find_or_create_by_username(sender) | |
#connect to fireeagle | |
user.init_fireeagle(app_id, consumer_key, consumer_secret) | |
begin | |
if body =~ /^auth/ | |
token = user.get_request_token | |
self.direct_message(sender, "ahoy, #{sender}! please visit #{user.authorization_url} to authorize firebot") | |
self.direct_message(sender, "once that's done, update your location like this: 'd firebot u Atlanta, GA'. Disclaimer: http://xrl.us/firebotdisclaimer") | |
elsif body =~ /^u (.*)/ | |
location = $1 | |
if user.authorized? || user.authorize | |
if user.update_location(location) | |
self.direct_message(sender,"updated your location to #{location}") | |
else | |
self.direct_message(sender,"that didn't work out. please try again later") | |
end | |
else | |
self.direct_message(sender, "you're not authorized yet. 'd firebot auth' to get started") | |
end | |
elsif body =~ /^q (.*)/ | |
username = $1 | |
queried_user = User.find_by_username(username) | |
if !queried_user.blank? && queried_user.authorized? | |
queried_user.init_fireeagle(app_id, consumer_key, consumer_secret) | |
location = queried_user.location | |
if !location.blank? | |
#TODO fix map link. stuff after spaces are being cut off | |
map_link = self.google_maps(URI.escape(location.gsub(',',' '))) | |
self.direct_message(sender, "last saw #{username} in #{location} (#{map_link})") | |
else | |
self.direct_message(sender, "we couldn't find #{username}. sorry!") | |
end | |
else | |
self.direct_message(sender, "#{username} isn't setup with firebot. why don't you ask them to follow us?") | |
end | |
elsif body =~ /^invite/ | |
invite = Invite.find_by_username(nil) | |
if invite.nil? | |
self.direct_message(sender, "sorry, I'm out of invites!") | |
else | |
invite.update_attributes!(:username => sender) | |
self.direct_message(sender, "http://fireeagle.com/ticket/" + invite.url) | |
end | |
elsif body =~ /^help/ || body =~ /^hi/ | |
self.direct_message(sender, "commands: \n'auth' to setup, \n'u Atlanta, Ga' to set location, \n'q username' to query another users location") | |
else | |
self.direct_message(sender, "firebot didn't understand your request: 'd firebot help' for instructions") | |
puts body.inspect | |
end # if body | |
rescue Exception => e | |
self.direct_message('jnewland', e.to_s + e.backtrace.join("\n")) | |
end | |
end | |
def direct_message(to, body) | |
xxx = Kconv.toutf8("d #{to} #{body}") | |
self.jabber_message("twitter@twitter.com", xxx) | |
end | |
def jabber_message(to, body) | |
puts "Sending: " + Time.now.to_s if DEBUG | |
puts to if DEBUG | |
puts body if DEBUG | |
puts "-"*80 if DEBUG | |
@client.deliver(to, body) | |
end | |
def google_maps(q) | |
"http://maps.google.com/maps?q=#{q}" | |
end | |
end # DangerDay | |
if $0 == __FILE__ | |
user = ARGV[0] | |
pass = ARGV[1] | |
sqlite = ARGV[2] | |
app_id = ARGV[3] | |
consumer_key = ARGV[4] | |
consumer_secret = ARGV[5] | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
ActiveRecord::Base.colorize_logging = false | |
ActiveRecord::Base.establish_connection( | |
:adapter => "sqlite3", | |
:dbfile => sqlite | |
) | |
if ARGV[0] == 'init' | |
ActiveRecord::Schema.define do | |
create_table :users do |table| | |
table.column :username, :string | |
table.column :request_token, :string | |
table.column :request_token_secret, :string | |
table.column :access_token, :string | |
table.column :access_token_secret, :string | |
end | |
add_index(:users, :username) | |
create_table :invites do |table| | |
table.column :username, :string | |
table.column :url, :string | |
end | |
end | |
elsif ARGV[0] == 'invites' | |
puts "Importing invites..." | |
open(ARGV[1]).read.split("\n").each do |invite| | |
puts invite | |
Invite.create(:url => invite) | |
end | |
puts "Done!" | |
else | |
puts "Connecting..." | |
bot = DangerDay.new(user, pass, app_id, consumer_key, consumer_secret) | |
puts "Connected!" | |
puts "Waiting for messages..." | |
bot.run | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment