メールによる Twitterの参照
Twitterへのメールからの投稿 - Rubyとか Illustratorとか SFとか折紙とか続き
それでメールによる Twitterの参照を受け付けるようにしてみた、参照結果をメールで送り返す。
#!/usr/bin/ruby # -*- coding: utf-8 -*- require 'nkf' require 'net/http' require 'net/smtp' Net::HTTP.version_1_2 Trusted = [ '<投稿者メールアドレス>', ] Twitt = Struct.new :acount, :password Twitts = { '<メールアドレス@の前>' => Twitt.new('<Twitterアカウント>', '<Twitterパスワード>') } sender, recipient, = ARGV File.open('/home/<ユーザ名>/projects/'+Time.now.strftime('%Y%m%d%H%M%S'), 'w'){ |f| f.puts sender, recipient, '' if Trusted.include? sender then #File.open('/home/<ユーザ名>/projects/'+Time.now.strftime('%Y%m%d%H%M%S'), 'w'){ |f| f.puts ARGV, $stdin.read } twitt = Twitts[sender.split('@')[0]] case recipient.split('@')[0] when 'twitter-update' then null_line = false doing = '' $stdin.readlines.each do |line| (doing = line.chomp; break) if null_line null_line = true if 1 == line.length end # $stdin.readlines.each do |line| f.puts doing request = Net::HTTP::Post.new('/statuses/update.json') request.basic_auth twitt.acount, twitt.password response = nil Net::HTTP.start('twitter.com',80) do |http| response = http.request(request, "status=#{NKF.nkf('-Jw', doing)}") end # Net::HTTP.start('twitter.com',80) do |http| f.puts response.body when 'twitter-timeline' then null_line = false doing = '' $stdin.readlines.each do |line| (doing = line.chomp; break) if null_line null_line = true if 1 == line.length end # $stdin.readlines.each do |line| count = /\A\d+/=~doing ? doing.to_i : 20 f.puts doing, count, '' request = Net::HTTP::Get.new('/statuses/friends_timeline.rss') request.basic_auth twitt.acount, twitt.password response = nil Net::HTTP.start('twitter.com',80) do |http| response = http.request(request, "count=#{count}") end # Net::HTTP.start('twitter.com',80) do |http| result = response.body.split("\n").select do |line| (line.include?('<description>')..line.include?('</description>')) ? true : false end.map do |line| line.sub(/^\s*<description>/, '').sub(/<\/description>\s*$/, '') end.map{ |line| line.gsub(/&#(\d+?);/){ [$1.to_i].pack('U') } } f.puts result Net::SMTP.start('localhost',25) do |smtp| smtp.send_mail <<-EOM, recipient, sender From: #{recipient} To: #{sender} Subject: #{recipient.split('@')[0]} Date: #{Time.now} Message-Id: <#{Time.now.to_i}.#{recipient}> #{NKF.nkf('-Wj', result.join("\n"))} EOM end # Net::SMTP.start('localhost',25) do |smtp| else end # case recipient.split('@')[0] else# if Trusted.include? sender f.puts $stdin.read end # if Trusted.include? sender }
大きく付け加わってるのはこの辺、when 節ひとつ。
when 'twitter-timeline' then null_line = false doing = '' $stdin.readlines.each do |line| (doing = line.chomp; break) if null_line null_line = true if 1 == line.length end # $stdin.readlines.each do |line| count = /\A\d+/=~doing ? doing.to_i : 20 f.puts doing, count, '' request = Net::HTTP::Get.new('/statuses/friends_timeline.rss') request.basic_auth twitt.acount, twitt.password response = nil Net::HTTP.start('twitter.com',80) do |http| response = http.request(request, "count=#{count}") end # Net::HTTP.start('twitter.com',80) do |http| result = response.body.split("\n").select do |line| (line.include?('<description>')..line.include?('</description>')) ? true : false end.map do |line| line.sub(/^\s*<description>/, '').sub(/<\/description>\s*$/, '') end.map{ |line| line.gsub(/&#(\d+?);/){ [$1.to_i].pack('U') } } f.puts result Net::SMTP.start('localhost',25) do |smtp| smtp.send_mail <<-EOM, recipient, sender From: #{recipient} To: #{sender} Subject: #{recipient.split('@')[0]} Date: #{Time.now} Message-Id: <#{Time.now.to_i}.#{recipient}> #{NKF.nkf('-Wj', result.join("\n"))} EOM end # Net::SMTP.start('localhost',25) do |smtp|
メールを送るのどうしようかと思った、ActionMailer とは言わないが TMail とか使おうかとも思ったが、Net::SMTP で手書きする。その為の require を冒頭に。
require 'net/smtp'
また、case 分岐処理のところ、コマンドメールアドレス前半だけ見れば良いよね、一々SMTPサーバのアドレスまで書かない。
case recipient.split('@')[0] when 'twitter-update' then
それはそれとして
本文一行目
count = /\A\d+/=~doing ? doing.to_i : 20
本文一行目が数字っぽかったら TimeLine の参照件数と見做すことにしよう。にしてもここの一行目文字列の変数名に doing は無いよね、update方面のコピペがたたる。
フリップフロップ
result = response.body.split("\n").select do |line| (line.include?('<description>')..line.include?('</description>')) ? true : false end.map do |line|
「
「end.map do 」はどうですか、僕は結構好き。
ユニコード系数値文字参照
end.map{ |line| line.gsub(/&#(\d+?);/){ [$1.to_i].pack('U') } }
メールの返信
Net::SMTP.start('localhost',25) do |smtp| smtp.send_mail <<-EOM, recipient, sender From: #{recipient} To: #{sender} Subject: #{recipient.split('@')[0]} Date: #{Time.now} Message-Id: <#{Time.now.to_i}.#{recipient}> #{NKF.nkf('-Wj', result.join("\n"))} EOM end # Net::SMTP.start('localhost',25) do |smtp|
メールを送る所は良いよね。Net::SMTP とはちょっとローレベルに戻り過ぎたか、まあ凝ったもんじゃなし勘弁して、大体見に行く方も Net::HTTP なんだし。
http://doc.loveruby.net/refm/api/view/library/net.smtp
課題
ちょっとコピーペースト、だからコードの繰り返し。今後コマンドメール対応増やすならなんとかしないと。
「case」分岐もどうかな、「send <メソッド名シンボル>」にしましょう。と言うことは何かクラスかモジュールを作った方が良いかな、それは何のどんなクラス(モジュール)なのだろう。
そう思うと、コマンドメール「twitter-timeline@」はどうか、Twitter APIに拠れば「friends_timeline」「user_timeline 」「mentions」くらいか、或は「statuses/friends_timeline」。どうかな。