世界を旅するゆるミンbotの実装 by Ruby

https://twitter.com/yurumin_の実装をまとめておく。

コード

#coding: utf-8
Process.daemon(true) if not $DEBUG
STDERR.reopen("/home/lastcat/for_yurumin/error.txt")
require 'rubygems'
require 'user_stream'
require 'twitter'
require 'pp'
require 'highline'
require 'mime-types'
require 'net/smtp'
require 'geocoder_jp'
require 'open-uri'
require 'RMagick'
include Magick

consumer_key = 'hogehoge'
consumer_secret = 'fufafuga'
oauth_token = 'foofoo'
oauth_token_secret = 'hoehoe'

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
client =  Twitter::Client.new


  def save_file(url)
    filename = File.basename(url)
    open(filename, 'wb') do |file|
      open(url) do |data|
        file.write(data.read)
      end
    end
    s = File::stat(filename)

    File.rename(filename,  "/home/lastcat/for_yurumin/sv.png")
  end

 #処理
#begin
loop do 
    #緯度、経度の整数乱数を生成して、streetviewを取得
    latitude = rand(180) - rand(90)
    lagtitude = rand(360) - rand(180)
    url = "http://maps.googleapis.com/maps/api/streetview?size=600x300&location=#{latitude},#{lagtitude}&heading=1708&pitch=-0.76&sensor=false"
    #puts url

    save_file(url)
    s = File::stat("/home/lastcat/for_yurumin/sv.png")
    #null画像ならループ飛ばしてもう一回 今のところサイズで判定
    if s.size==4868 then
       # raise
	next
    end
    #住所取得
    #geo = GeocoderJP.get("#{latitude},#{lagtitude}")
    #address = geo["google_maps"]

    #画像合成
    img1 = ImageList.new("/home/lastcat/for_yurumin/sv.png")
    img2 = ImageList.new("/home/lastcat/for_yurumin/yurumin.png")
    img3 = img1.composite(img2, CenterGravity, 50, 50, OverCompositeOp)
    img3.write("/home/lastcat/for_yurumin/composit.png")

 if latitude <= 0 then
      lat = "南緯#{-latitude}"
   else
      lat = "北緯#{latitude}"
   end

   if lagtitude <= 0 then
      lag = "西経#{-lagtitude}"
   else
         lag = "東経#{lagtitude}"
   end


   client.update_with_media("ゆるミンは#{lat},#{lag}地点まできています。", File.open("/home/lastcat/for_yurumin/composit.png"))

   sleep 1800
end
   #rescue => notfound
   #	retry
   #  end

仕様(やりたかったこと)

世界を旅して記念写真を撮ってつぶやいてくれるbot

具体的には、
①ランダムに緯度、経度を生成

ストリートビューで画像を取ってくる

③ゆるミン画像を合成する

④現在座標とともにつぶやく

という感じ。

実現例

実装解説

  • 90~90,-180~180の範囲で乱数生成 しかし何かがおかしい。気づいているが直さない。今度直します。

Google streetview はクエリが入ったURLを投げれば、(その場所のストリートビュー画像を返してくれる)
例:
http://maps.googleapis.com/maps/api/streetview?size=600x300&location=46.414382,10.013988&heading=151.78&pitch=-0.76&sensor=false
とりあえず座標を生成して画像を取ってくる。エラー画像の弾き方は手抜きなサイズ比較。
URLを指定して帰ってくる画像を保存してくれるメソッドがあるのでそれを使う。
参考URL:http://d.hatena.ne.jp/gan2/20080531/1212227507

使ってる所

  def save_file(url)
    filename = File.basename(url)
    open(filename, 'wb') do |file|
      open(url) do |data|
        file.write(data.read)
      end
    end
    s = File::stat(filename)

    File.rename(filename,  "/home/lastcat/for_yurumin/sv.png")
  end

  
  (url)
  s = File::stat("/home/lastcat/for_yurumin/sv.png")
  #null画像ならループ飛ばしてもう一回 今のところサイズで判定
  if s.size==4868 then
     # raise
     next
  end

あまり賢いとは言えない。いずれ改善。

    #画像合成
    img1 = ImageList.new("/home/lastcat/for_yurumin/sv.png")
    img2 = ImageList.new("/home/lastcat/for_yurumin/yurumin.png")
    img3 = img1.composite(img2, CenterGravity, 50, 50, OverCompositeOp)
    img3.write("/home/lastcat/for_yurumin/composit.png")

画像合成はrmagickというgemのなんか便利そうな奴を使った。
これをlinuxに入れると多分かなりの確率でエラーが出る。検索候補に出るレベル。
(多分)参考(にした)URL:http://qiita.com/items/6b1c6c7257042a159cc9
こっちは使い方のほう。正直中身は完全にブラックボックスとして使ってて恥ずかしい。
URL:http://d.hatena.ne.jp/SandRiver/20090422/1240358615
かなり画像扱うの便利そうだしいずれはちゃんと理解したい。どっかにドキュメントあるだろ有名そうだし。

そのまんま。当初画像付きpostするのにtwipicを使おうとしててAPI全部動かんしなんか他もロクなんないしで腐っててここに多分一番時間使った。
普通に公式(たぶん)のrubyAPIにあったというオチ。ググっても出てこないの罠っぽい。
勘を働かせて調べてみるべきだった。
レファレンスがあったというオチ:http://route477.net/w/?RubyTwitterJa

今後の展望

加えたい機能

住所を言わせたい

一応、

    #住所取得
    #geo = GeocoderJP.get("#{latitude},#{lagtitude}")
    #address = geo["google_maps"]

参考URL:https://github.com/yukinoraru/geocoder_jp
これである程度は引っ張ってこれる ただ、ストリートビュー存在のフィルターをくぐり抜けてもnotfoundを返す座標が合って二つ通すのめんどくさくてあきらめた。
上手く使えば多分できるのでまたのちのち 最悪jsonパースすればよい(偉そうに言ってるけどぜんぜんできない)。
参考URL:https://developers.google.com/maps/documentation/geocoding/?hl=ja

mapsで軌跡を追いたい。

ゆるミン管理用のサイトを作ってそこにいままでいった所とかでピン立てたりするんかな、多分。
前準備が出来たら簡単そうだけどサイト作るの…ウッ

移動を連続的にしたい

今のままではワープなので連続移動にしたい。
ただ、海をどう超えるんだろって感じ。多分たまにワープする感じになると思われる。
アーブダークション

リプに反応してその場所に行くとかやりたい

できるんかな、知らん。
メインの放浪との兼ね合いが不明。けど結構やりたい。

課題

範囲乱数おかしい

できるだけすぐ直します…

googleにリクエスト投げすぎて一日のアクセス限界超えて怒られる

要するに、もうちょいまともな所を選んで行くようにしろ、と言う話。常識的なことを言ってるようでアルゴリズムがあんまり思いつかない(世界範囲を前提にした場合の話ね)。

ブラックボックスすぎ

折を見て大事そうなやつはソース読む(読まない)。
えーぴーあいとじぇむってすごいですね!!!!!!!!!

くらいかなぁ…
まぁ頑張ります。

追記 Gemfile.lock

GEM
  remote: http://rubygems.org/
  specs:
    activesupport (3.2.13)
      i18n (= 0.6.1)
      multi_json (~> 1.0)
    faraday (0.8.7)
      multipart-post (~> 1.1)
    geocoder_jp (0.0.1)
      activesupport (~> 3.2.8)
    hashie (1.2.0)
    highline (1.6.18)
    i18n (0.6.1)
    mime-types (1.23)
    multi_json (1.7.2)
    multipart-post (1.2.0)
    nestful (1.0.1)
    oauth (0.4.7)
    rmagick (2.13.2)
    simple_oauth (0.2.0)
    twitter (4.6.2)
      faraday (~> 0.8, < 0.10)
      multi_json (~> 1.0)
      simple_oauth (~> 0.2)
    userstream (1.3.0)
      hashie (~> 1.2.0)
      oauth (~> 0.4.7)
      yajl-ruby (~> 1.1.0)
    yajl-ruby (1.1.0)

PLATFORMS
  ruby

DEPENDENCIES
  geocoder_jp
  highline
  i18n
  mime-types
  nestful
  oauth
  rmagick
  twitter
  userstream
_json (~> 1.0)
      simple_oauth (~> 0.2)
    userstream (1.3.0)
      hashie (~> 1.2.0)
      oauth (~> 0.4.7)
      yajl-ruby (~> 1.1.0)
    yajl-ruby (1.1.0)

ゆるミン元画像。
f:id:lastcat:20130423130059p:plain