4 # :title: Twitter Status Update for rbot
6 # Author:: Carter Parks (carterparks) <carter@carterparks.com>
7 # Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
9 # Copyright:: (C) 2007 Carter Parks
10 # Copyright:: (C) 2007 Giuseppe Bilotta
12 # Users can setup their twitter username and password and then begin updating
18 class TwitterPlugin < Plugin
19 Config.register Config::IntegerValue.new('twitter.status_count',
20 :default => 1, :validate => Proc.new { |v| v > 0 && v <= 10},
21 :desc => "Maximum number of status updates shown by 'twitter status'")
22 Config.register Config::IntegerValue.new('twitter.friends_status_count',
23 :default => 3, :validate => Proc.new { |v| v > 0 && v <= 10},
24 :desc => "Maximum number of status updates shown by 'twitter friends status'")
39 'X-Twitter-Client' => 'rbot twitter plugin'
43 # return a help string when the bot is asked for help on this plugin
44 def help(plugin, topic="")
45 return "twitter status [nick] => show nick's (or your) status, use 'twitter friends status [nick]' to also show the friends' timeline | twitter update [status] => updates your status on twitter | twitter identify [username] [password] => ties your nick to your twitter username and password | twitter actions [on|off] => enable/disable twitting of actions (/me does ...)"
48 # update the status on twitter
49 def get_status(m, params)
51 nick = params[:nick] || @registry[m.sourcenick + "_username"]
54 m.reply "you should specify the username of the twitter touse, or identify using 'twitter identify [username] [password]'"
58 user = URI.escape(nick)
60 count = @bot.config['twitter.status_count']
61 unless params[:friends]
62 uri = "http://twitter.com/statuses/user_timeline/#{user}.xml?count=#{count}"
64 count = @bot.config['twitter.friends_status_count']
67 auth << URI.escape(@registry[m.sourcenick + "_username"])
69 auth << URI.escape(@registry[m.sourcenick + "_password"])
72 uri = "http://#{auth}twitter.com/statuses/friends_timeline/#{user}.xml"
75 response = @bot.httputil.get(uri, :headers => @header, :cache => false)
82 rex = REXML::Document.new(response)
83 rex.root.elements.each("status") { |st|
84 # month, day, hour, min, sec, year = st.elements['created_at'].text.match(/\w+ (\w+) (\d+) (\d+):(\d+):(\d+) \S+ (\d+)/)[1..6]
85 # debug [year, month, day, hour, min, sec].inspect
86 # time = Time.local(year.to_i, month, day.to_i, hour.to_i, min.to_i, sec.to_i)
87 time = Time.parse(st.elements['created_at'].text)
89 # Sometimes, time can be in the future; invert the relation in this case
90 delta = ((time > now) ? time - now : now - time)
91 msg = st.elements['text'].to_s + " (#{Utils.secs_to_string(delta.to_i)} ago via #{st.elements['source'].to_s})"
94 author = Utils.decode_html_entities(st.elements['user'].elements['name'].text) + ": " rescue ""
96 texts << author+Utils.decode_html_entities(msg).ircify_html
99 # friends always return the latest 20 updates, so we clip the count
104 m.reply "could not parse status for #{nick}"
107 m.reply texts.reverse.join("\n")
110 m.reply "could not get status for #{nick}"
115 # update the status on twitter
116 def update_status(m, params)
119 unless @registry.has_key?(m.sourcenick + "_password") && @registry.has_key?(m.sourcenick + "_username")
120 m.reply "you must identify using 'twitter identify [username] [password]'"
124 user = URI.escape(@registry[m.sourcenick + "_username"])
125 pass = URI.escape(@registry[m.sourcenick + "_password"])
126 uri = "http://#{user}:#{pass}@twitter.com/statuses/update.xml"
128 msg = params[:status].to_s
131 m.reply "your status message update is too long, please keep it under 140 characters if possible, 160 characters maximum"
136 m.reply "your status message is longer than 140 characters, which is not optimal, but I'm going to update anyway"
139 source = "source=rbot"
140 msg = "status=#{CGI.escape(msg)}"
141 body = [source,msg].join("&")
143 response = @bot.httputil.post(uri, body, :headers => @header)
146 reply_method = params[:notify] ? :notify : :reply
147 if response.class == Net::HTTPOK
148 m.__send__(reply_method, "status updated")
150 m.__send__(reply_method, "could not update status")
154 # ties a nickname to a twitter username and password
155 def identify(m, params)
156 @registry[m.sourcenick + "_username"] = params[:username].to_s
157 @registry[m.sourcenick + "_password"] = params[:password].to_s
158 m.reply "you're all setup!"
161 # update on ACTION if the user has enabled the option
163 return unless m.action?
164 return unless @registry[m.sourcenick + "_actions"]
165 update_status(m, :status => m.message, :notify => true)
168 # show or toggle action twitting
169 def actions(m, params)
172 @registry[m.sourcenick + "_actions"] = true
175 @registry.delete(m.sourcenick + "_actions")
178 if @registry[m.sourcenick + "_actions"]
179 m.reply _("actions will be twitted")
181 m.reply _("actions will not be twitted")
187 # create an instance of our plugin class and register for the "length" command
188 plugin = TwitterPlugin.new
189 plugin.map 'twitter identify :username :password', :action => "identify", :public => false
190 plugin.map 'twitter update *status', :action => "update_status", :threaded => true
191 plugin.map 'twitter status [:nick]', :action => "get_status", :threaded => true
192 plugin.map 'twitter actions [:toggle]', :action => "actions", :requirements => { :toggle => /^on|off$/ }
193 plugin.map 'twitter :friends [status] [:nick]', :action => "get_status", :requirements => { :friends => /^friends?$/ }, :threaded => true