BitBar で私家版通勤タイマー (1) - portal shit! の続き。

JSON から情報を読み取って出力する奴は Ruby で書こうかなと思っていたんだけど、先日新しい上司と 1 on 1 をしていてどんな言語を使えるかの話になったときに Ruby と PHP とコールドフュ〜ジョン(と片手間 JavaScript )くらいしか使える言語がないということが判明してダメだと思ったので無理矢理 Go 言語で書いてみた。クソコードなので恥ずかしい。

package main

import (
    "encoding/json"
    "fmt"
    "os"
    "strconv"
    "strings"
    "time"
)

type Hour struct {
    Hour    string
    Minutes []string
}

func printLefts(m int, minutes []string, hour string) {
    for i := 0; i < len(minutes); i++ {
        mindes := strings.Split(minutes[i], " ")
        min := mindes[0]
        var Dest string
        if len(mindes) > 1 {
            Dest = mindes[1]
        }
        _m, _ := strconv.Atoi(min)
        left := _m - m
        if left > 0 && left < 30 {
            leftS := strconv.Itoa(left)
            takeM := fmt.Sprintf("%02d", _m)
            Str := leftS + " minutes left to " + hour + ":" + takeM
            if Dest != "" {
                Str = Str + " " + Dest
            }
            fmt.Println(Str)
        }
    }
}

func main() {
    decoder := json.NewDecoder(os.Stdin)
    timetable := make([]Hour, 0)
    decoder.Decode(&timetable)
    t := time.Now()
    h := t.Hour()
    m := t.Minute()
    var CurrentHour, NextHour Hour
    for i := 0; i < len(timetable); i++ {
        hour := timetable[i]
        _h, _ := strconv.Atoi(hour.Hour)
        if _h == h {
            CurrentHour = hour
            NextHour = timetable[i+1]
            break
        }
    }
    minutes := CurrentHour.Minutes
    printLefts(m, minutes, CurrentHour.Hour)
    if m > 44 {
        nextMinutes := NextHour.Minutes
        printLefts(m-60, nextMinutes, NextHour.Hour)
    }
}

こんな感じに表示される。

私家版通勤タイマー

あとはこれを BitBar で良い感じに読めるように出力内容を調整していけば良い。

Go 言語、 2 年くらい前に gyowitter っての作って Yo が来たら Twitter に晒すってのやってた以来に触った。変数のスコープとかがわかりづらかったし、 PHP っぽい雰囲気もある。やっぱり Ruby の方が書きやすいし好きだけど歯を食いしばって使ってみる。

以前は電車の本数多いところに住んでたので帰りの電車の時間とか気にしたことなかったけど、いまは郊外に住んでるので電車の本数少なくて、一本乗り遅れると駅で 20 分待たされたりする。特に遅くまで仕事してたりすると電車の本数がみるみる少なくなる。なので乗るべき電車に乗り遅れないように Yahoo! 乗換案内の通勤タイマーをよく使ってる。家まで帰る電車の発車時刻まであと何分かがカウントダウン表示されて便利。

ただ iPhone のウィジェットで見るとちょっともっさりしててだるい。 Pebble とかでサクッと確認できないかと思っているけど Pebble 入手して 10 ヶ月以上経つにもかかわらず Pebble 用のソフトを自分で作るという機運が高まらず今日に至る。

ある晩ふと、これって BitBar でできるんじゃねと思った。 BitBar は Mac のメニューバーに CLI で出力される情報を表示されることができるソフトで、 Netatmo Weather Station の計測値を表示するのに使っている。 Mac のメニューバーから二酸化炭素濃度や湿度確認できて便利。こんな感じ。これの通勤タイマー版が欲しい。

取り急ぎ時刻表の情報必要だけどちょっと探した感じでは簡単に時刻表取れるような API なかった。ので Yahoo! 乗換案内の時刻表をダウンロードして pup というコマンドラインの HTML パーサーで JSON 化し、それを jq に食わせて整形して良い感じの JSON にするという風にした。

# curl して HTML 取得
curl -s http://transit.yahoo.co.jp/station/time/28236/?gid=6400 | \
# HTML から必要な情報取り出して JSON 化
pup 'table.tblDiaDetail [id*="hh_"] json{}' | \
# JSON を良い感じに整形
jq '[.[] | { hour: .children[0].text, minutes: [.children[1].children[].children[].children[].children[].children | map(.text) | join(" ") ] }]'

得られる JSON はこんなのになる。(福岡市地下鉄空港線天神駅の姪浜方面の時刻一覧)

[
  {
    "hour": "5",
    "minutes": [
      "36",
      "42",
      "56 筑"
    ]
  },
  {
    "hour": "6",
    "minutes": [
      "8",
      "12 筑",
      "17",
      "26 筑",
      "34",
      "39",
      "43 筑",
      "56 筑"
    ]
  },
  ...,
  {
    "hour": "24",
    "minutes": [
      "6",
      "12 筑"
    ]
  }
]

これをコマンドラインで良い感じに表示するスクリプトを Ruby なり Shell Script なりで書いて BitBar に登録すればメニューバーから次の電車を確認できるようになり便利。