Twitter botのプログラムを晒してみる
どんなbotか
カラオケって、歌いたい曲が配信されてなかったりしますよね。
そのモヤモヤを救済するために、JOYSOUNDという超最高なカラオケ配信サービスが、配信リクエストを受け付けてくれています。リアルタイムリクエストです。投票で毎月200位までに入った曲が(なんらかの問題がないかぎり)配信されます。
投票にはポイントが必要で、このポイントを無駄にしないためには、なるべく200位ギリギリで通過させる戦略が求められます(ちょっと大げさか)。戦略を考えるにあたっては、順位の移り変わりをチェックしておくのが基本となります。
ぼくはキリンジというバンドのファンで、同じくキリンジファンの方々とTwitterで交流しているので、キリンジの曲の順位をチェックしてつぶやくTwitter botがあると便利だと思いました。実物はこれです。
事前準備
botのプログラムを書く前に、bot用のTwitterアカウントを用意したり、投稿に必要な各種キーを取得したり、といった事前準備が必要でした。下記ページの「OAtuhによるログイン方法」を参考にしました。
環境
早く公開したかったので、ぼくなりに早く書けるRubyを選びました。バージョンは 1.9.2-p136 です。
プログラム
美しくて堅牢なプログラムを書こうなどとは最初から思わなかったので、ざっと書いたら、こんな感じになりました。特に解説はしません。
# encoding: utf-8 require 'nokogiri' require 'open-uri' require 'twitter' require 'escape_utils' require 'escape_utils/url/rack' # Rack::Utils#escapeのwarningを防ぐ def utasuki_doc(singer) url = 'http://joysound.com/ex/utasuki/request/search.htm' + '?searchKbnGet=2' + "&searchKeyWordGet=#{EscapeUtils.escape_url(singer)}" + '&sortkey=8' Nokogiri::XML(open(url)) end def songs(doc) xpath = "//tr[@class='odd' or @class='even' or @class='evenlast']" doc.xpath(xpath).map do |row| {rank: row.xpath('./td[2]').text, title: row.xpath('./td[3]').text, votes: row.xpath('./td[6]').text} end end def songs_chunk(songs, hashtag) [] if songs.size == 0 songs_chunk = [[]] songs.each do |song| if status(songs_chunk.last + [song], hashtag).size <= 140 songs_chunk.last.push(song) else songs_chunk.push([song]) end end songs_chunk end def statuses(songs, hashtag) songs_chunk(songs, hashtag).map {|ss| status(ss, hashtag)} end def status(songs, hashtag) songs_text = songs.map {|s| song_text(s)}.join('、') "【うたスキ】#{songs_text} ##{hashtag} #{Time.now.strftime('%H:%M')}" end def song_text(song) "#{song[:rank]}位「#{song[:title]}」#{song[:votes]}" end def tweet(statuses) Twitter.configure do |config| config.consumer_key = '{consumer_key}' config.consumer_secret = '{consumer_secret}' config.oauth_token = '{oauth_token}' config.oauth_token_secret = '{oauth_token_secret}' end statuses.each do |status| Twitter.update(status) end end doc = utasuki_doc('キリンジ') songs = songs(doc) abort 'no songs' if songs.size == 0 statuses = statuses(songs, 'kiririku') tweet(statuses) puts 'done.'
下記のライブラリを使っています。
- twitter (1.1.1)
- nokogiri (1.4.4)
- escape_utils (0.1.9)
定期実行
上記のプログラムを /home/iwamot/projects/kirikara/bot.rb に保存し、crontabで毎時5分に実行しています。設定は下記の通りです。
$ crontab -l GEM_HOME=/home/iwamot/.rvm/gems/ruby-1.9.2-p136 5 * * * * /home/iwamot/.rvm/rubies/ruby-1.9.2-p136/bin/ruby /home/iwamot/projects/kirikara/bot.rb