指定場所の近くにいるレアポケモンを通知するTwitterbot
ポケモンレア度一覧のハッシュとソースを更新しました
指定場所の近くにいるbotを10分おきくらいに通知してくれるTwitter botを作りました。 最近は毎日研究室にいるのでとりあえず研究室周りのポケモンを通知してます。
公式の非公式APIを叩くのは規約違反になりそうで怖かったので、非公式サービスである pokevision の非公式APIを叩くことにしました。(負×負=正 みたいな考え方)
DeployToHeroku使って誰でも使えるようにすることも考えましたが、Pokevisionさんにアクセスしすぎて迷惑かけるのも申し訳ないのでやめました。 要望がめっちゃあったら考えます。
一応どうやってるか紹介しておくと、 https://pokevision.com/map/scan/$LATITUDE/$LONGITUDE
をgetすると {"status":"success","jobId":32文字の文字列}
みたいなjsonが返ってきます。
そしてこのjobIdを用いて、https://pokevision.com/map/data/$LATITUDE/$LONGITUDE/$jobId
をgetすると
{ "status": "success", "pokemon": [ { "id": 90613992, "data": "[]", "expiration_time": 1469438209, // ポケモンがいなくなる時間 "pokemonId": 102, // 図鑑No. "latitude": 35.706701501136, "longitude": 139.75326902249, // 緯度経度があるので距離も計算可能 "uid": "60188c3853d:19", "is_alive": true }, . . . ] }
みたいなjsonが返ってくるので、あとは好きに調理しましょう。
slackに投げたりするのもありですね。
レア度の判定のためにポケモン一覧とレア度一覧の2つのデータセットが必要なのですが、これを作るのが地味に面倒だったのでrubyのArrayとHashにしたものを置いておきます。
ご自由に使ってください。
(なお、レア度一覧は 【ポケモンGO 攻略】日本版判明!レアポケモン入手難易度一覧【ポケGO】 を元に作りました。 値が小さいほどレアで、進化ポケモンはとりあえず-1にしてあります。)
POKEMONS = [ "フシギダネ","フシギソウ","フシギバナ","ヒトカゲ","リザード","リザードン","ゼニガメ","カメール","カメックス","キャタピー","トランセル","バタフリー","ビードル","コクーン","スピアー","ポッポ","ピジョン","ピジョット","コラッタ","ラッタ","オニスズメ","オニドリル","アーボ","アーボック","ピカチュウ","ライチュウ","サンド","サンドパン","ニドラン♂","ニドリーナ","ニドクイン","ニドラン♀","ニドリーノ","ニドキング","ピッピ","ピクシー","ロコン","キュウコン","プリン","プクリン","ズバット","ゴルバット","ナゾノクサ","クサイハナ","ラフレシア","パラス","パラセクト","コンパン","モルフォン","ディグダ","ダグトリオ","ニャース","ペルシアン","コダック","ゴルダック","マンキー","オコリザル","ガーディ","ウインディ","ニョロモ","ニョロゾ","ニョロボン","ケーシィ","ユンゲラー","フーディン","ワンリキー","ゴーリキー","カイリキー","マダツボミ","ウツドン","ウツボット","メノクラゲ","ドククラゲ","イシツブテ","ゴローン","ゴローニャ","ポニータ","ギャロップ","ヤドン","ヤドラン","コイル","レアコイル","カモネギ","ドードー","ドードリオ","パウワウ","ジュゴン","ベトベター","ベトベトン","シェルダー","パルシェン","ゴース","ゴースト","ゲンガー","イワーク","スリープ","スリーパー","クラブ","キングラー","ビリリダマ","マルマイン","タマタマ","ナッシー","カラカラ","ガラガラ","サワムラー","エビワラー","ベロリンガ","ドガース","マタドガス","サイホーン","サイドン","ラッキー","モンジャラ","ガルーラ","タッツー","シードラ","トサキント","アズマオウ","ヒトデマン","スターミー","バリヤード","ストライク","ルージュラ","エレブー","ブーバー","カイロス","ケンタロス","コイキング","ギャラドス","ラプラス","メタモン","イーブイ","シャワーズ","サンダース","ブースター","ポリゴン","オムナイト","オムスター","カブト","カブトプス","プテラ","カビゴン","フリーザー","サンダー","ファイヤー","ミニリュウ","ハクリュー","カイリュー","ミュウツー","ミュウ" ].freeze RARITY = {"フシギダネ"=>4, "フシギソウ"=>-1, "フシギバナ"=>-1, "ヒトカゲ"=>4, "リザード"=>-1, "リザードン"=>-1, "ゼニガメ"=>4, "カメール"=>-1, "カメックス"=>-1, "キャタピー"=>6, "トランセル"=>-1, "バタフリー"=>-1, "ビードル"=>6, "コクーン"=>-1, "スピアー"=>-1, "ポッポ"=>6, "ピジョン"=>-1, "ピジョット"=>-1, "コラッタ"=>6, "ラッタ"=>-1, "オニスズメ"=>6, "オニドリル"=>-1, "アーボ"=>5, "アーボック"=>-1, "ピカチュウ"=>4, "ライチュウ"=>-1, "サンド"=>4, "サンドパン"=>-1, "ニドラン♂"=>5, "ニドリーナ"=>-1, "ニドクイン"=>-1, "ニドラン♀"=>5, "ニドリーノ"=>-1, "ニドキング"=>-1, "ピッピ"=>4, "ピクシー"=>-1, "ロコン"=>3, "キュウコン"=>-1, "プリン"=>4, "プクリン"=>-1, "ズバット"=>6, "ゴルバット"=>-1, "ナゾノクサ"=>6, "クサイハナ"=>-1, "ラフレシア"=>-1, "パラス"=>5, "パラセクト"=>-1, "コンパン"=>5, "モルフォン"=>-1, "ディグダ"=>4, "ダグトリオ"=>-1, "ニャース"=>4, "ペルシアン"=>-1, "コダック"=>4, "ゴルダック"=>-1, "マンキー"=>4, "オコリザル"=>-1, "ガーディ"=>4, "ウインディ"=>-1, "ニョロモ"=>5, "ニョロゾ"=>-1, "ニョロボン"=>-1, "ケーシィ"=>3, "ユンゲラー"=>-1, "フーディン"=>-1, "ワンリキー"=>3, "ゴーリキー"=>-1, "カイリキー"=>-1, "マダツボミ"=>5, "ウツドン"=>-1, "ウツボット"=>-1, "メノクラゲ"=>4, "ドククラゲ"=>-1, "イシツブテ"=>4, "ゴローン"=>-1, "ゴローニャ"=>-1, "ポニータ"=>4, "ギャロップ"=>-1, "ヤドン"=>4, "ヤドラン"=>-1, "コイル"=>4, "レアコイル"=>-1, "カモネギ"=>5, "ドードー"=>6, "ドードリオ"=>-1, "パウワウ"=>3, "ジュゴン"=>-1, "ベトベター"=>4, "ベトベトン"=>-1, "シェルダー"=>4, "パルシェン"=>-1, "ゴース"=>4, "ゴースト"=>-1, "ゲンガー"=>-1, "イワーク"=>4, "スリープ"=>4, "スリーパー"=>-1, "クラブ"=>5, "キングラー"=>-1, "ビリリダマ"=>5, "マルマイン"=>-1, "タマタマ"=>4, "ナッシー"=>-1, "カラカラ"=>4, "ガラガラ"=>-1, "サワムラー"=>2, "エビワラー"=>2, "ベロリンガ"=>3, "ドガース"=>4, "マタドガス"=>-1, "サイホーン"=>4, "サイドン"=>-1, "ラッキー"=>2, "モンジャラ"=>4, "ガルーラ"=>1, "タッツー"=>5, "シードラ"=>-1, "トサキント"=>5, "アズマオウ"=>-1, "ヒトデマン"=>5, "スターミー"=>-1, "バリヤード"=>1, "ストライク"=>3, "ルージュラ"=>4, "エレブー"=>2, "ブーバー"=>3, "カイロス"=>5, "ケンタロス"=>1, "コイキング"=>5, "ギャラドス"=>-1, "ラプラス"=>2, "メタモン"=>0, "イーブイ"=>4, "シャワーズ"=>-1, "サンダース"=>-1, "ブースター"=>-1, "ポリゴン"=>2, "オムナイト"=>2, "オムスター"=>-1, "カブト"=>2, "カブトプス"=>-1, "プテラ"=>2, "カビゴン"=>2, "フリー<e3><82><b6>ー"=>0, "サンダー"=>0, "ファイヤー"=>0, "ミニリュウ"=>3, "ハクリュー"=>-1, "カイリュー"=>-1, "ミュウツー"=>0, "ミュウ"=>0}
以下ソース(エラー処理とか全くしてないので気をつけてください)
require 'twitter' require 'net/http' require 'json' BLD2_LAT = 35.714165568996115 BLD2_LONG = 139.76182758808136 class Pokemon attr_accessor :name, :distance, :rarity, :left_time POKEMONS = [ "フシギダネ","フシギソウ", ... ].freeze RARITY = {"フシギダネ"=>4, "フシギソウ"=>-1, ...} def initialize(hash) expiration_time = hash['expiration_time'] @left_time = Time.at(expiration_time) - Time.now pokemon_id = hash['pokemonId'] @name = POKEMONS[pokemon_id-1] @rarity = RARITY[@name] latitude = hash['latitude'] longitude = hash['longitude'] @distance = calc_distance(latitude, longitude) end def to_string "#{@name}: #{@distance.to_i}m #{@left_time.to_i}秒" end private def calc_distance(lat, lng) y1 = lat * Math::PI / 180 x1 = lng * Math::PI / 180 y2 = BLD2_LAT * Math::PI / 180 x2 = BLD2_LONG * Math::PI / 180 earth_r = 6378140 deg = Math::sin(y1) * Math::sin(y2) + Math::cos(y1) * Math::cos(y2) * Math::cos(x2 - x1) distance = earth_r * (Math::atan(-deg / Math::sqrt(-deg * deg + 1)) + Math::PI / 2) end def <=>(pokemon) self.distance <=> pokemon.distance end end class Bld2PokemonsFetcher attr_accessor :pokemons SCAN_END_POINT = "https://pokevision.com/map/scan/#{BLD2_LAT}/#{BLD2_LONG}" DATA_END_POINT = "https://pokevision.com/map/data/#{BLD2_LAT}/#{BLD2_LONG}/" def initialize @pokemons = [] end def fetch # binding.pry scan_uri = URI.parse(SCAN_END_POINT) scan_json = Net::HTTP.get(scan_uri) job_id = JSON.parse(scan_json)['jobId'] # 待ってあげないとin_progressとか言われる sleep 3 data_uri = URI.parse(DATA_END_POINT + job_id.to_s) data_json = Net::HTTP.get(data_uri) @pokemons = JSON.parse(data_json)['pokemon'].map { |e| Pokemon.new(e) }.select{|pokemon| pokemon.rarity <= 4 && pokemon.distance < 100}.sort end end class PokemonTweet attr_accessor :tweet def initialize @cli = Twitter::REST::Client.new do |config| config.consumer_key = '********************' config.consumer_secret = '********************' config.access_token = '********************' config.access_token_secret = '********************' end end def update pokemons = Bld2PokemonsFetcher.new.fetch.uniq{|p| p.name} return if pokemons.empty? sentence = "@show_me_tech 二号館近くにいるレアポケモンは\n#{pokemons[0...5].map(&:to_string).join("\n")}\nだよ!" @cli.update(sentence) end end