この記事はプリキュア Advent Calendar 2013 の 12 月 9 日のものである.
2013 年 6 月 1 日,とある大物 Twitter ユーザの方が突如「スマイルプリキュア」と呟いた.
どうやら娘さんが勝手にスマホを使って,検索をしようとしたそうである.
面白いなと思って自分も勝手にスマイルプリキュアとつぶやく環境を作ろうとした.
それにあたってどうしても守りたかったのが次の点であった.
- 既存の bot サービスは使いたくない
- via twittbot とか表示されるようなクソダサイものにしたくなかった
- 出来れば「ラーメン大陸」の意味不明さに乗っかって「プリキュア大陸」にしたかった
- つぶやかれる時間と内容を完全にランダムにしたい
- 毎日決まって 18:00 ぴったりにつぶやかれる等というようなものにしたくなかった
- 自分でもつぶやかれる時間も内容も分からないようにしてドキドキしたかった
- 自分のサーバで cron を使いたくない
- いつミスって消してしまうともしれないものに依存したくなかった
さて精一杯がんばって考えてまず思い浮かんだのが,普段から愛用している Heroku である.
Heroku には無料で使える Redis アドオンがある.これで tweet が発せられる時間を完璧に管理出来るのではなかろうか.
Heroku で動かせる Ruby には clockwork という cron よりもイケてるツールがある.
また同じく Ruby には twitter 用のライブラリもある.
よし,これでいこう.けってーい!
ではまずは Heroku の環境をゲットしよう.
heroku apps:create precure-continent
幸いにしてまだこの名前は取られていなかった.当たり前だ.なお precure-tairiku
も一応念の為既に私が取っている.多分一生役に立たないであろう.
次は,clockwork のための環境作りだ.Gemfile
と clock.rb
を用意する.
source 'https://rubygems.org'
gem 'clockwork', '0.5.4'
require 'rubygems'
require 'clockwork'
handler do |job|
puts "#{Time.now}"
end
every(1.minutes, '')
bundle install
して Gemfile.lock
を用意したら,Heroku のための (正確には foreman のための) Procfile
を用意しよう.
clock: bundle exec clockwork clock.rb
それではこれらを Git リポジトリとして管理するようにしてやり,Heroku へ push だ.
ここまで出来れば,ひとまず 1 分ごとに現在時刻をログに吐き出す環境が用意出来たことになる.Heroku 上でプロセスを増やして,こいつが動けるようにしてやる.
heroku ps:scale clock=1
これでもう,心のビートは止められない.あとは,その 1 分ごとに動くたびに,tweet を発するかどうかを管理すれば良いことになる.
自分はここで,Redis のテストも兼ねて,次の tweet まで残り何分かをカウントダウンしていくことにしてみた.
…とまぁ色々試しながらやっていったのだが,そろそろ解説するのも面倒くさくなってきたし,ちまちまと差分確認しつつ書くのもここらが我慢の限界になってきたので,現在のコードそのものを貼ってしまうことにする.Gemfile
と clock.rb
は以下の通りとなった.
なお,一部伏せた状態にしてある.
source 'https://rubygems.org'
gem 'clockwork', '0.5.4'
gem 'twitter', '4.8.1'
gem 'redis', '3.0.4'
# coding: utf-8
require 'rubygems'
require 'clockwork'
require 'twitter'
require 'uri'
require 'redis'
include Clockwork
Twitter.configure do |config|
config.consumer_key = ENV['CONSUMER_KEY']
config.consumer_secret = ENV['CONSUMER_SECRET']
config.oauth_token = ENV['OAUTH_TOKEN']
config.oauth_token_secret = ENV['OAUTH_SECRET']
end
uri = URI.parse(ENV['REDISTOGO_URL'])
REDIS = Redis.new host: uri.host, port: uri.port, password: uri.password
handler do |job|
left_count = (REDIS.get :left_count).to_i
now = Time.now
left_count -= 1
if left_count % 60 == 0
puts("now: #{now}; left_count: #{left_count}")
end
if left_count <= 0
tweet = [
'title0',
'title1',
'title2',
'title3',
].sample
Twitter.update(tweet)
puts("now: #{now}; tweet: #{tweet}")
tw_time = start_hour * 60 + (rand * (end_hour - start_hour) * 60).to_i
left_count = tw_time + 24 * 60 - (now.hour + 9) * 60 - now.min
puts("new left_count: #{left_count}")
end
REDIS.set :left_count, left_count
end
every(1.minutes, '')
ドキドキを守るために,title0, title1, title2, title3, start_hour, end_hour
が実際どういう値になっていたのかはクシャポイさせていただく.
Twitter を利用するためのライブラリの使い方とか,Redis の使い方とか,色々あるのだが,つまり left_count
に残りのカウントを保存し,それを毎分減らしていき 0 になったら tweet する,tweet したら left_count
を次の tweet までの新しい残りカウントに変更する,というだけである.
Twitter の認証のための環境変数は
heroku config:set CONSUMER_KEY=<YOUR_CONSUMER_KEY>
heroku config:set CONSUMER_SECRET=<YOUR_CONSUMER_SECRET>
heroku config:set OAUTH_SECRET=<YOUR_OAUTH_SECRET>
heroku config:set OAUTH_TOKEN=<YOUR_OAUTH_TOKEN>
のようにして追加し (※これらの値の取得方法も割愛させていただく),Redis のアドオンは
heroku addons:add redistogo:nano
のようにして追加した.
ただこの手法,tweet 時刻が結構ぶれる.
しかし致命的にぶれるわけではないので,自分は今のところ気にしていない.それにいくらか遅れたところで,新しい left_count
の算出は現在時刻を使って行うのでズレが蓄積していくことはぶっちゃけありえない.
残りカウント数ではなく tweet 予定時刻を設定しておいて,現在時刻がそれを過ぎていれば tweet する,という実装でもいいと思う.ただ自分は前述した通り Redis のテストもしたかったので,毎分読み込みと書き込みを行うという実装を試してみたのだ.
そしてプリキュア大陸というサービスは,この tweet を第一の tweet として稼働が始まり,昨日 12 月 8 日も立派に唐突に何の脈絡も無く勝手に「スイートプリキュア」と tweet をしている.
なお,お気付きになられなかったかもしれないが,当初は「スイートプリキュア♪」という正確な表記であったのが今は「スイートプリキュア」という表記になっている.この辺,ちょくちょく変えたり変えたり変えなかったり色々している.私は自分のリポジトリを見ていつ何をしたか把握しているのだが,それは非公開である.
また,12 月 1 日に「ハピネスチャージプリキュア」ともつぶやくようになったが,その変更自体はその前からあった.
単純な乱数とは言え,制御の及ばないものは見ていて楽しい.しかも自分で一日一回しか作動しないようにしてあるので,長い目で見なければならないのも胸のキュンキュン止まらない.
ちなみに完全に無料で動かせている.絶好調なり.
ただ,個人的に clock.rb
はもう少し綺麗に (特に left_count
再計算の部分が…) したい.どうせならテストも書いて gem にしたい.そうすればきっとみんなウルトラハッピーだと思う.
そんなわけで,自動プリキュアタイトル tweet サービス「プリキュア大陸」のはじまりの話をここに終え,プリキュア Advent Calendar 2013 12 月 9 日の記事とさせていただく.