akiranetの日々淡々と頑張っていこう

akiranetのコンピューターと遊ぶ

hubotを用いた楽しいslackLife(実践編)

ak1raです!
Hubotでslacklifeを快適にしようって思って、研究室に導入して楽しんでます!
最近まで1人GithubFlowをしてやっていましたが、無理矢理仲間が増えました!

前回、hubotを用いた楽しいslackLife(入門編)はこちら

開発したものはこちらです!
accueil

ちなみに、 accueil とは、フランス語で 歓迎, もてなし です! アクイーユっていうパンケーキが人気のお店もあるので、おすすめです笑

accueilに実装した機能

1. アニメ情報取得

huboco 上記のサイトを参考にしました。上記のものでは、
* 今期放送中のアニメの一覧を表示
* 今期のアニメをタイトルで検索

を表示してくれるものでした。 自分は、指定した年に放送したアニメを出してくれるスクリプトを書きました。

# 指定年のアニメ一覧
  robot.respond /(anime|アニメ)\s+(\d{4})$/i, (msg) ->
#    msg.send msg.match[2]
    msg.send "http://api.moemoe.tokyo/anime/v1/master/#{msg.match[2]}"
    url = "http://api.moemoe.tokyo/anime/v1/master/#{msg.match[2]}"
    msg.http(url).get() (err, res, body) ->
      if err? or res.statusCode isnt 200
        return msg.reply("#{ERR_MSG}\n```\n#{err}\n```")
      animes = JSON.parse(body)
      t = new table
      for anime in animes
          t.cell('URL', anime.public_url)
          t.cell('Title', anime.title)
          t.newRow()
      if t.rows.length > 0
        return msg.reply('```\n' + t.print().trim() + '\n```')
      msg.reply(NiL_MSG)

これは、anime 2016と行うと、2016年のアニメ一覧を表示してくれる。 2016のところは、2個目の正規表現のところを用いているので、msg.match[2]で表現している。

npmの使用モジュールとしては、
* moment = require(‘moment’)
* table = require(‘easy-table’)
を用いていて、 easy-table は簡単なDBのテーブルを作成ができる!便利!

アニメのAPIサーバの使い方を利用して、
http://api.moemoe.tokyo/anime/v1/master/#{msg.match[2]}によって、 http://api.moemoe.tokyo/anime/v1/master/2016となります。

ここで、アニメAPIサーバーからのレスポンスは以下のようなものとなる。

 [AkiRa:MBP-3-/~/bot/accueil] %
(`・∀・´) >>> curl http://api.moemoe.tokyo/anime/v1/master/2016 | jq .       [~/bot/accueil][master]
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  9866  100  9866    0     0  37606      0 --:--:-- --:--:-- --:--:-- 37656
[
  {
    "id": 281,
    "title": "機動戦士ガンダム サンダーボルト"
  },
  {
    "id": 282,
    "title": "プリンス・オブ・ストライド オルタナティブ"
  },
  {
    "id": 283,
    "title": "無彩限のファントム・ワールド"
  },

上記のように、JSON形式で返ってくるので、animes = JSON.parse(body)で扱える!

2. 映画館

登録映画館の公開映画と上映時間を表示のスクリプト

スクレイピングを行うために、 cheerio = require 'cheerio'を使用していて、jQuery風に取得できます!

THEATER_IDS = JSON.parse(process.env.HUBOT_THEATER_IDS ? '["11652","11610", "11625"]') 上記でどこの映画館の公開映画などを表示するのか決められる! たとえば、TOHOシネマズ新宿だと、 https://movies.yahoo.co.jp/theater/11652/でできる!!

HEATER_IDS.reduce(((promise, theaterId) ->
      promise.then (result) ->
        baseUrl = 'http://movies.yahoo.co.jp'
        url = "#{baseUrl}/theater/#{theaterId}/"
        request(url).then (r) ->
          $ = cheerio.load r.body
          movies = []
          theater = $('h1').text().trim()
          $('#schedule_list .listview__element').each ->
            e = $ @
            title = e.find('h3 a').text().trim()
            url = baseUrl + e.find('h3 a').attr('href')
            times = []
            e.find('ul.list-inline li').each ->
              l = $ @
              time = l.find('.btn-schedule').contents().filter(->
                @type is 'text'
              ).text().trim()
            times.push time
            movies.push { title, url, times }
            result.push { theater, movies }
            result

これは、 https://movies.yahoo.co.jp/theater/11652/のHTMLのタグ<h1>や<h3>から映画館名と映画タイトルをスクレイピングしています。 上映時間は、<a class="btn-schedule>を用いて、入手しています。

実行結果は以下のように出力されます

ccueil> accueil theater
accueil> TOHOシネマズ 新宿
                   ガーディアンズ・オブ・ギャラクシー:リミックス(3D・字幕版・IMAX)            09:00  12:00  15:00  18:00  21:00
                   ガーディアンズ・オブ・ギャラクシー:リミックス(3D・字幕版・MX4D)            16:00  19:00  22:00
                                                                                                       18:30
                   アンタッチャブル (字幕版)                                                        10:00
                   ワイルド・スピード ICE BREAK(字幕版・MX4D)                          09:30  12:30

3. GitHubのIssueのオープン・クローズド・一覧表示

repo  = "MaRuG/practice"

module.exports = (robot) ->
  github = require('githubot')(robot)

  robot.respond /issue list/i, (msg) ->
    github.get "https://api.github.com/repos/#{repo}/issues", {}, (issues) ->
      issues = issues.sort (a,b) -> a.number > b.number
      texts = ["https://github.com/#{repo}/issues"]
      for i in issues
        texts.push "[#{i.number}] #{i.title}"
      text = texts.join '\n'
      msg.reply "I'm listing up your issues\n#{text}"

  robot.respond /issue create (.+) body (.+)/i, (msg) ->
    who = msg.message.user.name
    title= msg.match[1]
    body = msg.match[3]
    if body is undefined then body = ""
    query_param =
      title: title
      body: "#{title}\n\ncreated by #{who} & hubot\n\n#{body}"
      labels: ["fromHubot"]
    github.post "https://api.github.com/repos/#{repo}/issues", query_param, (issue) ->
      text = "Sure! I created an issue for you\n#{issue.html_url}"
      msg.reply text

  robot.respond /issue close (.*)/i, (msg) ->
    github.patch "/repos/#{repo}/issues/#{msg.match[1]}", {state: "closed"}, (issue, error) ->
      if error then console.log error
      text = "OK. I closed #{issue.title} issue"
      msg.reply text

これを使うには、GITHUB_TOKENを登録する必要がある

$ curl -i https://api.github.com/authorizations -d '{"scopes":["repo"]}' -u "自分のユーザー名"
$ heroku config:set HUBOT_GITHUB_TOKEN=token_value

githubotを用いると便利!

4. ランチタイムの時間に通知と店をランダムで表示

cronJob = require('cron').CronJob
random = require('hubot').Response::random


module.exports = (robot) ->


  robot.hear /(lunch)/i, (msg) ->
    lunch = msg.random [
      '一平ソバ'
      '清華'
      'コンビニ'
      'スエヒロ'
      '東館食堂'
      'サクラキッチン'
    ]
    msg.reply "#{lunch}"


  new cronJob('0 40 12 * * 1-5', () ->
    
    messages =  [
      '一平ソバ'
      '清華'
      'コンビニ'
      'スエヒロ'
      '東館食堂'
      'サクラキッチン'
    ]

    message = messages[Math.floor(Math.random() * messages.length)]
    
    robot.send( '#12th-member', message)
  ).start

決まった時刻(平日の12:40)に、ランチの時間を知らせて、店の場所を発言してくれるようにしてます! でも食べたい物とお金の事情により、この通知はガン無視してます笑

この定期実行を行っているのは、cronJob = require('cron').CronJob
new cronJob(' 秒 分 時 日 月 曜日(月-金 = 1-5)'), () -> で表示できます!

5. Yahoo!電車情報での遅延情報

https://github.com/hotatekaoru/myHubotScripts/blob/master/train-info.coffeeを参考にしました。

以下に運行情報からスクレイピングを行っています。 https://transit.yahoo.co.jp/traininfo/gc/13/

例として山手線は、[https://transit.yahoo.co.jp/traininfo/detail/21/0/]をあげる 以下のコードurlに山手線のURLを入れる。

  searchTrainCron = (url) ->
    cheerio.fetch url, (err, $, res) ->
      title = "#{$('h1').text()}"
      if $('.icnNormalLarge').length
        robot.send {room: '#12th-member'}, "#{title}は遅れてないよ。はい。"
      else
        info = $('.trouble p').text()
        robot.send {room: '#12th-member'}, "#{title}は遅れているみたい。\n#{info}"

平常運転なら、<span class="icnNormalLarge">がある。 もし遅延していたら、

<dd class="trouble">
<p>20:10頃、秋津駅で発生した人身事故の影響で、現在も一部列車に遅れや運休が出ています。<span>(5月23日 23時20分掲載)</span></p>

というのがあるので、そこを表示するようにしている。

まとめ

 今回実際に便利そうな機能を人の真似ながらですが、ソースコードについて理解できるよう勉強しました。今後は、在室管理をSlackで管理しHubotに呼びかけると、研究室にいる人と徹夜の人を表示してくれるようなものを作りたいと思います。

参考

天気情報
電車の情報を教えてくれる
3時間毎にcronを実行
huboco
bouznya
githubot用いて、issueを立てる
trim()について