この記事は GetWild Advent Calendar 2016 の17日目の記事です。
はじめに
「Get Wild」がリリースされたのは1987年。それから30年という月日が流れようとしていますが、僕たちはまだ愛のパズルを解けないままです。いや、解けないのではなく解こうとしていないのではないでしょうか?僕たちはもっと常日頃から愛のパズルを解き続けなければいけないのではないでしょうか?
仕事に追われているうちに大事なことを忘れてしまう。毎日に疲れ果て、ついには思い出すこともなくなってしまう。もうそんなことはやめましょう。いつも目に見える場所に解かなければいけないパズルがあるべきなのです。
そう、あなたのコンピューターのメニューバーに。
BitBar
BitBar はmacOSのメニューバーの機能を拡張するユーティリティです。どんなことができるのかは私の最近の記事にサラッと書いてあるので、読んでもらえると大変ありがたいです。
- BitBarで自分の人生の残り時間を常に意識する
- BitBarで自分のやるべきタスクを常に意識する
- BitBarでMySQLサーバーの状態を常に意識する
- BitBarでPostgreSQLサーバーの状態を常に意識する
端的に言うと、標準出力に文字列を出力するプラグインを書くだけでメニュー項目が作れてしまう革命的なユーティリティです。
仕様
どうすれば、愛のパズルを解くヒントが得られるのでしょうか?もちろんそれは Get Wildを聴く ことです。しかし、もしかしたら動画の方がより多くのヒントが得られるかもしれません。そこでメニューバーにYouTubeの動画リストを表示し、いつでもすぐにGet Wildな動画を観られるようにします。
動画リストは検索結果の上位5件でよいでしょう。このリストは6時間ごとに更新します。
実装
そんなこんなで実装したプラグインがこちらです。
//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 を利用しています。jQueryのようにDOMを操作できるライブラリで、馴染みのある操作感なのがうれしいです。Webクライアントの機能も持ち合わせているので、これだけで簡単なクローラーを作成できてしまいます。
実行
BitBarの公式ページでは、Golangで書かれたプログラムをInterpreterとして実行できると謳っているのですが、私の環境では期待通りに動作しませんでした。しょうがないのでコンパイルしたバイナリを使用してください。
前述のプログラムをGistに上げているので、 curl
などで取得しましょう。コンパイルしたバイナリは .cgo
という拡張子を付けます。所定のBitBar Pluginディレクトリに配置してください。
$ 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
その実行結果が下の画像です。
メニューバーに銃のemojiが表示されているので、こちらをクリックします。表示されたメニュー項目の一つを選択するとデフォルトのブラウザが該当ページを開きます。
要望
このプラグインを作成してみてまず思ったことは、こんなもので本当に愛のパズルが解けるのだろうか?ということです。
- 一度観た動画は観たことがわかるようにしたい。
- 新しい動画がリストに追加されたら通知を出してほしい。
- 動画のサムネイルを出してほしい。
- そもそもバイナリを配布してほしい。
パッと思いついただけでもこれくらいの機能がないと愛のパズルが解けそうな気がしません。自分で作り始めたんだから自分で実装しなければいけませんね。でも後でリポジトリを作っておくのでPull Requestをお待ちしています。
追記
リポジトリを作成しました。
おわりに
愛のパズルを解く旅が再び始まりました。僕たちは Get Wild and Tough に生きていかなれけばいけないのです。これからは新しい友達、Golangとともに毎日愛のパズルを解くことに邁進したいと思います。