A twitter group bot for Colorado Software Summit
I have created a twitter group and an associated pair of bots for use during this year’s Colorado Software Summit.
Listening to @swsmt
The twitter group is @swsmt. If you use twitter, and want to follow tweets about the conference, then just follow @swsmt.
A few minutes later, you should also see @swsmt start following you. The main reason for this is to allow you to direct message the group. If you remove @swsmt from your followers, it should also then quit following you.
Tweeting to @swsmt
To tweet about the conference, or to send a message to everyone following @swsmt, you can do one of several things:
- Direct message the swsmt group (For example: D swsmt blah).
- Reply to @swsmt, or otherwise mention @swsmt in a tweet.
- Use the #swsmt hashtag in a tweet.
- Mention "SoftwareSummit" (one word) in your tweet - this will also pick up anyone tweeting a link to softwaresummit.com
When my bot sees any of the above, it will retweet them to the @swsmt account, so that everyone following the group will then see them.
The bots
Twitter has a pretty decent REST API, and I also found a nifty ruby library (twitter) wrapping that. Throwing together a couple of scripts was pretty easy after that.
Syncing friends
The first script I wrote syncs the group’s friends with followers. Keeping these in sync lets the follow act kind of like a subscription to the group.
The script just grabs both the followers and friends lists, and adds/removes based on the diffs between them.
The script is:
#!/usr/bin/env ruby
# synchronize followers/followed
# we do this because followers (those who 'join this group') will see
# all the messages, but we need to make them our friend so they
# can direct message the group
# http://twitter.rubyforge.org/
# sudo gem install twitter
require 'rubygems'
require 'twitter'
group_name = 'swsmt'
passwd = 'XYZZY' # not really :)
# Log in
group = Twitter::Base.new(group_name,passwd)
# TODO only returns 100
# when we get more than 100, this will probably stop working very well
friends = group.friends.collect{ |f| f.screen_name }
followers = group.followers.collect{ |f| f.screen_name }
# followers who are not the group's friend yet (add them)
followers.each do |f|
unless friends.include? f then
begin
puts "Adding friend (following) #{f}"
group.create_friendship f
rescue
puts "Unable to add friend #{f}: #{$!}"
end
end
end
# friends who no longer follow the group (remove them)
friends.each do |f|
unless followers.include? f then
begin
puts "Removing friend (following) #{f}"
group.destroy_friendship f
rescue
puts "Unable to remove friend #{f}: #{$!}"
end
end
end
Retweeting script
The retweet script searches recent tweets for @swsmt, #swsmt, or softwaresummit, and retweets that to @swsmt. It then grabs any recent direct messages, and retweets those.
Here’s that script:
#!/usr/bin/env ruby
# retweet messages to the @group
# we'll search for messages with a group hashtag #group or
# referencing the @group
# as well as some other keywords.
# also retweet any direct messages to the group
# run this via cron every couple of minutes to keep the group updated
# http://twitter.rubyforge.org/
# sudo gem install twitter
require 'rubygems'
require 'twitter'
group_name = 'swsmt'
passwd = 'XYZZY' # not
# search for hashtags, group ref, or conference name
search_query = "##{group_name} OR @#{group_name} OR SoftwareSummit"
# Log in
group = Twitter::Base.new(group_name,passwd)
def retweet(group, from, text, id, lastid)
retweet = "Via @#{from}: #{text}"
retweet = retweet[0,140] + '...' if retweet.length > 159
puts retweet
begin
group.post(retweet)
id.to_i > lastid.to_i ? id.to_i : lastid
rescue
puts "Error retweeting: #{$!}"
lastid
end
end
# Keep track of the last ids we retweeted
searchid_file = File.expand_path('~/.group_retweet.searchid')
last_searchid = nil
last_searchid = File.open(searchid_file){ |f| f.gets.to_i } if File.exists?(searchid_file)
begin
# search for #group hashtag etc
# TODO this will only return the 50 most recent - if there's too much traffic,
# we will drop some.
Twitter::Search.new(search_query).since(last_searchid).per_page(50).sort {|a,b| a['id'] <=> b['id'] }.each do |m|
# skip messages from the group itself (probably our last retweet)
unless m['from_user'] == group_name then
last_searchid = retweet group, m['from_user'], m['text'], m['id'], last_searchid
end
end
ensure
File.open(searchid_file, 'w'){ |f| f.puts last_searchid } unless last_searchid.nil?
end
directid_file = File.expand_path('~/.group_retweet.directid')
last_directid = nil
last_directid = File.open(directid_file){ |f| f.gets.to_i } if File.exists?(directid_file)
begin
# now grab any new direct messages and retweet them
# TODO this will only return the 20 most recent - if there's too much traffic,
# we will drop some
group.direct_messages(:since_id=>last_directid).sort {|a,b| a.id <=> b.id }.each do |m|
last_directid = retweet group, m.sender_screen_name, m.text, m.id, last_directid
end
ensure
File.open(directid_file, 'w'){ |f| f.puts last_directid } unless last_directid.nil?
end
I’m running both of these via cron. I just turned this on, so we’ll see how it goes.
Technorati Tags: colorado software summit, conference, hashtag, bot, ruby, softwaresummit, twitter
2 comments