hubotでslackに天気予報を投げる


#やりたいこと
- slackにyahoo!天気予報のスクリーンショットを毎日表示させたい

#方針
- hubotにやらせる
- nightmareでスクリーンショットを撮る
- 画像はgyazoにアップする
- pm2でデーモン化する

#実装

##nodeインストール

nodebrewを使用します。
8系を選んだのはなんとなくです。

```
nodebrew ls-remote
nodebrew install v8.11.3
nodebrew use v8.11.3
node -v
```

##hubotインストール＆セットアップ

```
npm i -g hubot yo generator-hubot coffee-script

mkdir slack_hubot
cd slack_hubot
yo hubot
```

あとでpm2使ってデーモン化するとき用に
bin/hubot を bin/hubot.sh にリネームしておきます。
[参考1](https://qiita.com/SiriusArc7/items/88de7363c9e130ba0ebf)
[参考2](https://cncgl.github.io/2015/07/09/Hubot-Slack-VPS.html)

```
mv bin/hubot bin/hubot.sh
```

##nightmareインストール

```
npm i coffee-script
npm i electron
npm i nightmare
```

nightmareが使用しているerectronのために
xvfbを用意しておきます。

```
sudo yum -y install gtk2
sudo yum -y install libXScrnSaver
sudo yum -y install GConf2

sudo yum -y install xorg-x11-server-Xvfb

sudo yum -y install xorg-x11-server-Xorg xterm
sudo yum -y install xorg-x11-drv-vesa xorg-x11-drv-evdev xorg-x11-drv-evdev-devel
```

##そのほかインストール

```
npm i gyazo-api
npm i cron
```

##スクリプト

```script/weather.coffee
# Description:
#   weather.
#

Nightmare = require 'nightmare'
Gyazo = require 'gyazo-api'
cron = require('cron').CronJob

url = 'https://weather.yahoo.co.jp/weather/13/4410.html'
filename = "/tmp/_weather.png"
client = new Gyazo(process.env.GYAZO_TOKEN)

module.exports = (robot) ->
  job = new cron '0 0 10 * * *', () =>
    nightmare = new Nightmare({ show: true })

    nightmare
      .viewport(1000,1000)
      .goto(url)
      .wait("body")
      .evaluate ()=>
        rect = document.querySelector('.forecastCity').getBoundingClientRect()
        return {
          left:   Math.round(rect.left)
          top:    Math.round(rect.top)
          right:  Math.round(rect.right)
          bottom: Math.round(rect.bottom)
          width:  Math.round(rect.width)
          height: Math.round(rect.height)
        }
      .then (rect)=>
        return nightmare
          .screenshot(filename, {
            x: rect.left,
            y: rect.top - 38,
            width: rect.width,
            height: rect.height + 38
          })
          .end()
      .then () =>
        client.upload(filename)
          .then (res) =>
             robot.send {room: "random"}, "東京の天気：" + res.data.permalink_url
  job.start()

```

##動作テスト

テスト前にスクリプトのcron設定は
```job = new cron '0 * * * * *', () =>``` などにしておいて下さい。


```
export HUBOT_LOG_LEVEL=debug
export HUBOT_SLACK_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx
export GYAZO_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx

xvfb-run ./bin/hubot.sh -a slack -n [bot名]
```

\#randomにこんな感じの絵が表示されれば成功です。

![slack.png](https://qiita-image-store.s3.amazonaws.com/0/108345/4eacf15f-6079-2c25-37d2-b92ff9a4f099.png)

##pm2を使ってデーモン化する

このままだと
コンソールを落とすとスクリプトが止まってしまうので
pm2を使用します。

```
npm i -g pm2

pm2 start --interpreter xvfb-run -f ./bin/hubot.sh -x --name [pm2プロセス名] -- -a slack -n [bot名]
```

#簡単な補足
- 毎朝10時にpostされます。
- ```.forecastCity``` が天気予報部分に当たってるstyleです。38というマジックナンバーは「今日明日の天気」分の高さです。
- styleに対して ```getBoundingClientRect()``` して切り出し位置を算出しているので、yahoo!天気予報がstyle名変えたりすると対応が必要になります。


#激闘の記録
- 最初はcentos6上で実装しようとしていたが、electronが動作しないことが判明
- nightmare1.x系だとelectronを使用しないので、そちらで実装しようとしたが、screenshotを行う時にcropができなかったので、諦めてcentos7系に移行
- pm2上でxvfb-runさせる方法にたどり着くまでの長く険しい道のり


#あとがき
「こうすればもっと簡単にできる」とか
あれば是非教えて下さるとうれしいです。