BitBarでひとりでは解けない愛のパズルを常に意識する

この記事は [GetWild Advent Calendar 2016](http://qiita.com/advent-calendar/2016/getwild) の17日目の記事です。

## はじめに

「Get Wild」がリリースされたのは1987年。それから30年という月日が流れようとしていますが、僕たちはまだ愛のパズルを解けないままです。いや、解けないのではなく解こうとしていないのではないでしょうか？僕たちはもっと常日頃から愛のパズルを解き続けなければいけないのではないでしょうか？

仕事に追われているうちに大事なことを忘れてしまう。毎日に疲れ果て、ついには思い出すこともなくなってしまう。もうそんなことはやめましょう。いつも目に見える場所に解かなければいけないパズルがあるべきなのです。

そう、あなたのコンピューターのメニューバーに。

## BitBar

[BitBar](https://github.com/matryer/bitbar) はmacOSのメニューバーの機能を拡張するユーティリティです。どんなことができるのかは私の最近の記事にサラッと書いてあるので、読んでもらえると大変ありがたいです。

- [BitBarで自分の人生の残り時間を常に意識する](http://qiita.com/artifactsauce/items/1caca90e91c6ca90ebbf)
- [BitBarで自分のやるべきタスクを常に意識する](http://qiita.com/artifactsauce/items/2f933a1dbddf19ab008a)
- [BitBarでMySQLサーバーの状態を常に意識する](http://qiita.com/artifactsauce/items/d111bb1e6676f235094d)
- [BitBarでPostgreSQLサーバーの状態を常に意識する](http://qiita.com/artifactsauce/items/445535ea8a58253c2f28)

端的に言うと、標準出力に文字列を出力するプラグインを書くだけでメニュー項目が作れてしまう革命的なユーティリティです。

## 仕様

どうすれば、愛のパズルを解くヒントが得られるのでしょうか？もちろんそれは **Get Wildを聴く** ことです。しかし、もしかしたら動画の方がより多くのヒントが得られるかもしれません。そこでメニューバーにYouTubeの動画リストを表示し、いつでもすぐにGet Wildな動画を観られるようにします。

動画リストは検索結果の上位5件でよいでしょう。このリストは6時間ごとに更新します。

## 実装

そんなこんなで実装したプラグインがこちらです。

```go:main.go
//usr/bin/env go run $0 $@; exit

package main

import (
	"fmt"
	"log"

	"github.com/PuerkitoBio/goquery"
	"net/url"
)

type Config struct {
	ListItemNumber int
	SearchPhrase   string
}

type Provider struct {
	Name       string
	BaseUrl    string
	SearchPath string
}

type Video struct {
	Title string
	Path  string
	Id    string
}

func GetWildAndTough(p Provider, c Config) {
	doc, err := goquery.NewDocument(GetSearchUrl(p, c))
	if err != nil {
		log.Fatal(err)
	}

	doc.Find("h3.yt-lockup-title").Each(func(i int, s *goquery.Selection) {
		if i > c.ListItemNumber {
			return
		}
		v := Video{}
		v.Title = s.Find("a").Text()
		v.Path, _ = s.Find("a").Attr("href")
		Url := p.BaseUrl + v.Path
		fmt.Printf("%s | href=%s\n", v.Title, Url)
	})
}

func GetSearchUrl(p Provider, c Config) string {
	return p.BaseUrl + p.SearchPath + "?search_query=" + url.QueryEscape(c.SearchPhrase)
}

func GetConfig() Config {
	c := Config{}
	c.ListItemNumber = 5
	c.SearchPhrase = "Get Wild"
	return c
}

func GetProvider() Provider {
	p := Provider{}
	p.Name = "YouTube"
	p.BaseUrl = "https://www.youtube.com"
	p.SearchPath = "/results"
	return p
}

func main() {
	p := GetProvider()
	c := GetConfig()

	fmt.Println(":gun:")
	fmt.Println("---")
	GetWildAndTough(p, c)
	fmt.Println("---")
	fmt.Println("Refresh | refresh=true color=#C0C0C0")
}
```

実装言語は、完全なる思いつきで、まともに書いたこともないGolangを選択しました。新しい言語を覚えられたらいいかなー程度の理由です。

定数とかメソッドの責任範囲とか拡張性とか、気にしなきゃいけないことも多いんですが、まあ全然できていません。とりあえず動いたという状態です。すみません。時間がなかったんです。年末ですから。

### スクレイピング

動画リストの取得にはYouTube APIを使わず、通常のWeb画面をスクレイピングすることにしました。こんなしょうもない目的のために、まず最初にOAuth認証画面が立ち上がって…みたいなことはやってられんなーというのがその理由です。ちょっとお行儀が悪いかもしれませんが、今回の目的に対しては十分でしょう。

スクレイピングには [PuerkitoBio/goquery](https://github.com/PuerkitoBio/goquery) を利用しています。jQueryのようにDOMを操作できるライブラリで、馴染みのある操作感なのがうれしいです。Webクライアントの機能も持ち合わせているので、これだけで簡単なクローラーを作成できてしまいます。

## 実行

BitBarの公式ページでは、Golangで書かれたプログラムをInterpreterとして実行できると謳っているのですが、私の環境では期待通りに動作しませんでした。しょうがないのでコンパイルしたバイナリを使用してください。

前述のプログラムをGistに上げているので、 `curl` などで取得しましょう。コンパイルしたバイナリは `.cgo` という拡張子を付けます。所定のBitBar Pluginディレクトリに配置してください。

```console
$ mkdir /PATH/TO/WORK/DIR && cd $_
$ curl -O https://gist.githubusercontent.com/artifactsauce/852a95bc22dad2a06e76ffc4b2fcc6eb/raw/cfffe5dd7298b50928b44620d9864f0be7c8b6db/getwild.6h.go
$ go build -o /PATH/TO/BitBar/Plugin/getwild.6h.cgo
```

その実行結果が下の画像です。

<img width="696" alt="getwild-menu.png" src="https://qiita-image-store.s3.amazonaws.com/0/5823/4eab6e7f-ee37-6c94-d88a-da5e3e08c83c.png">

メニューバーに銃のemojiが表示されているので、こちらをクリックします。表示されたメニュー項目の一つを選択するとデフォルトのブラウザが該当ページを開きます。

## 要望

このプラグインを作成してみてまず思ったことは、こんなもので本当に愛のパズルが解けるのだろうか？ということです。

- 一度観た動画は観たことがわかるようにしたい。
- 新しい動画がリストに追加されたら通知を出してほしい。
- 動画のサムネイルを出してほしい。
- そもそもバイナリを配布してほしい。

パッと思いついただけでもこれくらいの機能がないと愛のパズルが解けそうな気がしません。自分で作り始めたんだから自分で実装しなければいけませんね。でも後でリポジトリを作っておくのでPull Requestをお待ちしています。

**追記**

[リポジトリ](https://github.com/artifactsauce/bitbar-plugin-getwild)を作成しました。

## おわりに

愛のパズルを解く旅が再び始まりました。僕たちは Get Wild and Tough に生きていかなれけばいけないのです。これからは新しい友達、Golangとともに毎日愛のパズルを解くことに邁進したいと思います。