Humanity

Edit the world by your favorite way

open-browser.vim で Windows Subsystem for Linux 上の Vim から URL 開けるようになった

github.com

これで WSL 上であろうとなかろうと意識せず URL を開けるはずです。 最近は WSL の Vim ばっかり使ってるので個人的にうれしい機能追加です(追加したの自分だけど)。


WSL は Windows の世界と分断されてると思い込んでたのですが、 /mntWindowsファイルシステムを触れるのは知ってたものの、 Windows の実行ファイル(PE フォーマットの実行ファイル)も起動できるのは知りませんでした。 bash から /mnt/c/Windows/System32/notepad.exe とか開けるんですね。

というわけで直接 Windows で動いてる Vim *1 でも叩いてる rundll32.exe を直接叩いて URL を渡すだけでした。あっけない。

*1:この表現は誤解を招くような… WSL も同じサブシステム上で動いてるし。なんて言えばいいんだ?

Go のバージョンマネージャー gvm で gvm install したら「ERROR: Failed to compile」って言われた時

github.com

issue には上げたけど日本語でも書く。 結果から言うと自分が README.md よく読んでなかっただけ。 でも gvm ももうちょっと気を利かせてくれてもいいのになーと思ったので上の issue でお願いしたという経緯です。

解決法

Go 1.5 以上をコンパイルする場合は GOROOT_BOOTSTRAP って環境変数を定義する必要があります。 これは .bash_profile かなんかで

export GOROOT_BOOTSTRAP=$GOROOT

して gvm install すればいいのですが、「GOROOT?そんなん定義したことないんだけど…」って人もいるかと思います (現に今は GOROOT 環境変数定義する必要はないらしいです)。

GOROOTJava にとっての JAVA_HOME みたいなもので、go コマンド等のベースパスを指定するものです。

で、じゃあどうすればいいのかというと、go コマンド自体に聞いてしまえばいいとのこと。

export GOROOT_BOOTSTRAP=$(go env GOROOT)

これで GOROOT_BOOTSTRAP には go コマンド等のベースパスが入ります。 もちろん go コマンドに PATH が通ってないとダメなので後述するように先に PATH を設定してやります。

どう設定すればいいか

自分の Go 関連の .bash_profile を載せておきます(今回の話に関係ないのもありますが)。

# Go 1.5 以下で vendoring が有効になる
# http://yoru9zine.hatenablog.com/entry/2016/02/02/054922
export GO15VENDOREXPERIMENT=1

if true; then
  # gvm の go コマンドを使う
  [[ -s "/home/tyru/.gvm/scripts/gvm" ]] && source "/home/tyru/.gvm/scripts/gvm"
  export GOROOT_BOOTSTRAP=$(go env GOROOT)
else
  # system 標準の go コマンドを使う
  export GOPATH="$HOME/go"
  export PATH="$GOPATH/bin:$PATH"
fi

true, false で gvm の Go か system の Go かを切り替えられるようにしてあります。

Go 言語の習作に watchevent ってファイルシステム監視するやつ作った(おまけに Subsonic で音楽ファイルを追加・削除されたタイミングでスキャンさせる方法)

習作って言っても以前 Go 触ってたことはありましたが、 そのツールを作ったこと自体忘れてたぐらい記憶が抜け落ちていたので、改めて Go に再入門しました。

作ったもの

使い方は README.md 読んでください(まだ不十分だと思いますが、分からない点は issue に上げてくれると助かります…)。

github.com

各種バイナリは GitHub release のページにあります(watchevent コマンドしか入ってません)。

きっかけ

自分は Subsonic というストリーミングサーバーを自宅に立てて運用してますが、 いくつか不満がありました。

  1. flac ファイル特有の現象なのかは分からないが)flac ファイルを再生すると曲が終わっても次の曲に行ってくれない
    • 曲の時間が明らかに長かったりするので、終わりが正しく取得できてない?
  2. 音楽フォルダのスキャンが一日一回に限られている
    • 曲が追加されたら一定時間後に自動的にスキャンしてほしい
  3. 最近のバージョンのコードはクローズド(version 6.0-beta1 以降)

Subsonic に不満があったので OSS 版の Libresonic をインストールしてみた - Humanity

ちなみに上記記事では同じくストリーミングサーバの Libresonic に移行したと書いてるのですが、色々問題点があって結局戻ってきました。 それについては気が向いたら詳しく別記事で書きますが、なんと言っても第一の理由は今回利用する API が Libresonic では対応してなかったからです。 それが音楽フォルダのスキャンを開始する API です。

Subsonic では音楽フォルダに mp3 ファイルをポンと置いてもすぐ Web に現れる訳ではなく、 音楽フォルダのスキャンを行う必要があります。 しかしこのスキャンのタイミングがデフォルトでは夜の3時のみで、不便なことに定期スキャンは1日1回だけという制限があります(時間は変えられます)。

もちろんこれでは不便すぎるので Subsonic にはアップロード機能があって、 アップロードした音楽ファイルであれば即座に認識されます。 しかしアップロードするために ZIP で固めるのが面倒だったり、 何となくディレクトリ構造は手動で決めたいという欲求から自分はアップロード機能は使ってません。

しかしそれでは手元にある音楽ファイルを音楽フォルダに移動してすぐ聴きたいという時に不便です。 幸いスキャンは設定画面から手動でも行うことができるので、音楽フォルダに移動するたびにわざわざスキャンのボタンをポチっていましたが、できれば自動化したい。

そこで SubsonicREST API のページを眺めていると前述のスキャンを行うエンドポイントがあると書いてありました。 ならファイルの変更を検知して curl で叩くツール作ればいいのでは?ということで作りました。

Systemd で管理する

自分は watchevent は Systemd で管理して使ってますので、 ついでにそのインストール手順を書きます。

まずバイナリを GitHub release のページからダウンロードしてきて、 どこでもいいですが /opt/watchevent に置きます。

$ # ダウンロード URL は OS, arch によって変えてください
$ curl -LO https://github.com/tyru/go-watchevent/releases/download/v0.0.1/watchevent-v0.0.1-linux-amd64.tar.gz
$ tar xzf watchevent-v0.0.1-linux-amd64.tar.gz
$ sudo mkdir /opt/watchevent/
$ sudo install -o root -g root -m 0755 watchevent-v0.0.1-linux-amd64/watchevent /opt/watchevent/watchevent

次に各設定ファイルを作ります。

/etc/systemd/system/watchevent.service

[Unit]
Description=Watchevent

[Service]
Type=simple
EnvironmentFile=-/etc/default/watchevent
ExecStart=/opt/watchevent/watchevent -c /etc/watchevent/watchevent.yml $DIRECTORY
PrivateTmp=true

[Install]
WantedBy=multi-user.target

/etc/default/watchevent

DIRECTORY="-d {監視対象のディレクトリ}"

ちなみにこんな風に2個以上監視することもできます。

DIRECTORY="-d dir1 -d dir2"

/etc/watchevent/watchevent.yml

action:
  - name: post-subsonic-rescan
    on: [all]
    # 30s after latest file change, access to Subsonic API
    interval: 30s
    interval_action:
      - on: [all]
        do: cancel
    # {user}, {token}, {salt} は変えてください。{token}, {salt} については後述
    run: curl 'http://localhost:4040/rest/startScan?u={user}&t={token}&s={salt}&v=1.15.0&c=watchevent-curl'

log:
  level: "info"
  encoding: "console"
  #encoding: "json"
  encoderConfig:
    messageKey: "msg"
    levelKey: "level"
    timeKey: "time"
    nameKey: "name"
    callerKey: "caller"
    stacktraceKey: "stacktrace"
    levelEncoder: "capital"
    timeEncoder: "iso8601"
    durationEncoder: "string"
    callerEncoder: "short"
  outputPaths:
    - "stdout"
  errorOutputPaths:
    - "stderr"

ちなみに Subsonic API の解説もしておくと、curl コマンドの引数の URL の {token} はこんな風に求めます({salt} は適当に決めてください)。

$ echo -n '{パスワード}{salt}' | md5sum 

で出力された MD5 値を token に指定します。 うまくいかなければ u (username), p (password), c (client) パラメータだけでもいけます(がセキュリティ上よろしくない)。

上記設定ファイルを作った後、

$ sudo systemctl daemon-reload
$ sudo systemctl enable watchevent
$ sudo systemctl start watchevent

として起動します。 ちゃんと動作してるかログが見たい方は

$ journalctl -ef -u watchevent

とかすると watchevent の出力が tail -f されるので眺めるといいかもしれません。