GoogleHomeをスプラトゥーンアシスタントにする #2 Twitterからステージ情報の取得

#はじめに

Google Homeを買ったはいいものの、テレビ無し、外出ない、家電使わない自分には少々物足りないので
生活の大半を占めるスプラトゥーンのアシスタントをGoogle Homeには勤めてもらいます。

みたいな事を[書いた](https://qiita.com/tak_km/items/c06f45c6692dceb9258d)ので、その続きです。
[GoogleHomeをDialogflow(旧:API.ai)でスプラトゥーンアシスタントにする](https://qiita.com/tak_km/items/c06f45c6692dceb9258d)
#実装する機能

スプラトゥーンは3つのゲームモードがあり、それぞれ時間によってステージが異なります。
確認するにはスマホアプリかまたはゲーム内アナウンスで確認する必要があるので、これをハンズフリーで確認できるようにしたいと思います。
<img width="1284" alt="スクリーンショット 2017-10-16 17.55.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/b9607648-2e17-0264-5055-803bbbf5acfa.png">

実装する機能のイメージ↓
>僕「**ステージ 〇〇(ゲームモード)**」

>GoogleHome「**〇〇のステージは××(ステージ名)です**」

また、ゲームモードの「ガチマッチ」「リーグマッチ」ではルールが3種類あるのでそれも確認できるようにします。

#使用ツール・環境

- Google Home
- [Dialogflow](https://dialogflow.com)
- python3.5.2
- [twython](https://twython.readthedocs.io/en/latest/)

webhookの置き場に[heroku](https://heroku.com)を使用し、
前回とは違い、IFTTTは使用せずDialogflowとwebhookのみで実装します。

#ステージ情報の取得
現在配信されているステージ情報を取ってきます。
公式アプリから閲覧できる[イカリング2](https://www.nintendo.co.jp/switch/aab6a/online/index.html)からプロキシをごにょごにょして取ってきてもいいんですが、
[【スプラトゥーン2】イカリング2の戦績データをPCブラウザで無理矢理閲覧する](http://s2terminal.hatenablog.com/entry/2017/07/23/203831)

世の中には[便利なBot](https://twitter.com/splatoon2_stage)を作っている人がいるのでこちらのBotのツイートから取得しようと思います。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">10/16 15:00～<br>▼ナワバリ<br>タチウオパーキング、モズク農園<br><br>▼ガチエリア<br>バッテラストリート、海女美術大学<br><br>▼リーグ：ガチヤグラ<br>ガンガゼ野外音楽堂、コンブトラック <a href="https://t.co/hL7og5epFO">pic.twitter.com/hL7og5epFO</a></p>&mdash; スプラトゥーン2 ステージ情報bot (@splatoon2_stage) <a href="https://twitter.com/splatoon2_stage/status/919802614614704128?ref_src=twsrc%5Etfw">2017年10月16日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

ツイート取得機能は応用が効きそうですしね~~(イカリングからの取得が面倒そうだからという訳では無いです)~~

##twythonをインストール

TwitterAPIを叩くのに今回はtwythonを使います。
初期設定は[こちら](https://syncer.jp/Web/API/Twitter/REST_API/)参照
[Twitter REST APIの使い方](https://syncer.jp/Web/API/Twitter/REST_API/)

どうせ大した事しないのでtwython使うまでも無い気はしますが...
`$pip install twython`

スクリプトを書きます。

```python:twython.py
from twython import Twython, TwythonError


APP_KEY = "取得したAPI Key"
APP_SECRET = "取得したAPI Secret"
OAUTH_TOKEN = "取得したAccess Token"
OAUTH_TOKEN_SECRET = "取得したAccess Token Secret"

def getStage(num,mode):
    twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
    #ツイートを取得したいTwiiterアカウントのID
    screen_name = "splatoon2_stage"
    results = twitter.get_user_timeline(screen_name=screen_name,count=5)
    date = list(filter(lambda s:s != '', results[num]["text"].replace("▼","").replace("、","と").split()))
    time = date[1].replace((b'\xef\xbd\x9e').decode('utf-8'),"から")
    nawabari = date[3]
    gachi_mode = date[4]
    gachi_stage = date[5]
    league_mode = date[6].replace("リーグ：","モードは")
    league_stage = date[7]
    if mode == "ナワバリ":
        return time + nawabari
    elif mode == "ガチマッチ":
        return time+"モードは"+gachi_mode+"ステージは"+gachi_stage
    elif mode == "リーグマッチ":
        return time +league_mode +"ステージは"+ league_stage

if __name__ == '__main__':
    print(getStage(0,"ガチマッチ")+"です")
```
これで、現在のステージ名とガチマッチ・リーグマッチの場合は「ガチホコ」「ガチエリア」「ガチヤグラ」等のゲームモードを出力できるようになりました。

`出力例`
<img width="619" alt="スクリーンショット 2017-10-16 17.14.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/cfa57d83-5df0-0509-58e5-a9b0df2ba353.png">

これを後は[前回](https://qiita.com/tak_km/items/c06f45c6692dceb9258d)作成したpythonファイルに書き加えればOKです。

```python:webhook-dialogflow.py
from __future__ import print_function
from future.standard_library import install_aliases
install_aliases()

from urllib.parse import urlparse, urlencode
from urllib.request import urlopen, Request
from urllib.error import HTTPError

import json
import os

from flask import Flask
from flask import request
from flask import make_response, jsonify
import gspread
from oauth2client.service_account import ServiceAccountCredentials

from twython import Twython, TwythonError
APP_KEY = "取得したAPI Key"
APP_SECRET = "取得したAPI Secret"
OAUTH_TOKEN = "取得したAccess Token"
OAUTH_TOKEN_SECRET = "取得したAccess Token Secret"

# Flask app should start in global layout
app = Flask(__name__)


@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json(silent=True, force=True)
    result = req.get("result")
    parameters = result.get("parameters")
    text = ""
    if req.get("result").get("action") == "getSpreadSheet":
        text = getSpreadSheet(parameters.get("weapon_name"))
    if req.get("result").get("action") == "getStage":
        text = getStage(0,parameters.get("mode"))+"です"
    r = make_response(jsonify({'speech':text,'displayText':text}))
    r.headers['Content-Type'] = 'application/json'
    return r
    
def getStage(num,mode):
    twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
    screen_name = "splatoon2_stage"
    results = twitter.get_user_timeline(screen_name=screen_name,count=5)
    date = list(filter(lambda s:s != '', results[num]["text"].replace("▼","").replace("、","と").split()))
    time = date[1].replace((b'\xef\xbd\x9e').decode('utf-8'),"から")
    nawabari = date[3]
    gachi_mode = date[4]
    gachi_stage = date[5]
    league_mode = date[6].replace("リーグ：","モードは")
    league_stage = date[7]
    if mode == "ナワバリ":
        return time + nawabari
    elif mode == "ガチマッチ":
        return time+"モードは"+gachi_mode+"ステージは"+gachi_stage
    elif mode == "リーグマッチ":
        return time +league_mode +"ステージは"+ league_stage

def getSpreadSheet(weapon_name):
    #
    #省略　前回のスクリプト参照
    #
    return text

if __name__ == '__main__':
    port = int(os.getenv('PORT', 5000))

    print("Starting app on port %d" % port)

    app.run(debug=False, port=port, host='0.0.0.0')
```

では、次にwebhookを送信するDialogflowの設定に行きましょう。

#Dialogflowのセッティング
詳しくは[前回](https://qiita.com/tak_km/items/c06f45c6692dceb9258d)のを見て頂くとして、新規に設定する部分を載せます。
前回のBotに機能を追加する場合は`Intents`に新しく返答を登録すればOKです。

###Intents
`Intents`で入力の受け取りや失敗した際の返答を登録します。
新しく`stage`を作成。`CREATE INTENT`で新規intentを登録可能です。
<img width="1144" alt="スクリーンショット_2017-10-18_22_06_40.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/c43faee8-fd44-7a75-25fe-50a8ce18b2ce.png">
(`成績`が前回作成したintent)



今回はユーザーの発言が「ステージ」だった場合にBotが反応し、
「ステージ」の後に続く部分を`mode`として入力で受け取ります。

<img width="655" alt="スクリーンショット 2017-10-16 16.40.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/24ff32bd-e05a-312f-ef67-e4dd7bd9b799.png">
Actionには`getStage`と入力。JSONのこの部分を上記のpythonスクリプトは見て前回のwebhookと分岐させています。
<img width="671" alt="スクリーンショット 2017-10-16 18.06.21.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/899475cb-d89a-c714-f27e-762047bec80a.png">


###Entities
入力として受け取る単語を`Entities`から登録します。
今回もスプラトゥーンのデータベースは無いようなのでポチポチ登録しましょう。
<img width="660" alt="スクリーンショット 2017-10-16 16.40.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/d79337ed-d845-9207-b300-cf9283ef1de9.png">

###Fulfillment
前回と変更点はありません。
webhookを流すurlを入力しておきましょう。
<img width="512" alt="20171012132542.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/bef0eca6-7e72-0fc7-af6f-0fce9cd58217.png">

これでセッティングは終了です。

#テストする
Dialogdlowのコンソール右側にテキストを入力してテストしましょう。
<img width="363" alt="スクリーンショット 2017-10-16 16.40.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/54085/711938f8-bc1c-7120-f43e-f78eea87b52b.png">
ステージが出てきました！
`action`,`parameter value`も問題なさそうですね。

#完成
動作の確認はこちらの動画から↓
[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/93EYnWGrsHg/0.jpg)](http://www.youtube.com/watch?v=93EYnWGrsHg)

#おわりに
今回はゲームモードを取得しましたが、先日開催された**フェス**やもう1つのゲームモード**サーモンラン**に対応していないのでそこら辺やろうかと思います。
でも別々のTwitterBotから取得するぐらいならイカリングから読み出した方がいい気も…先は長いですね。
スプラトゥーン以外にもTwitterとの連携は便利そうなので使っていきたいです。

良きスプラトゥーンライフを！~~(フェスは負けました)~~

#参考
- [Raspberry Pi2 + Twython でニュース bot を作ろう（step1：Twitter API を使うための準備）](https://www.indetail.co.jp/blog/raspberry-pi2-twython-newsbot/)
- [Twythonで遊ぼう　その1](http://frontier-of-curiosity.org/2015/08/29/twython%E3%81%A7%E9%81%8A%E3%81%BC%E3%81%86%E3%80%80%E3%81%9D%E3%81%AE%EF%BC%91/)
- [Twitter REST APIの使い方](https://syncer.jp/Web/API/Twitter/REST_API/)