EmacsからiTunesを操作する方法
ワンタンスープ、おいしいです。Gehirn News ライターの KOBA789 です。
今回は Emacs のお話です。Emacs といえば世界の100割くらいの人が使ってることで有名な環境
です。
さて、私は業務中、よくヘッドホンで音楽を聞いています。作業は SSH でつないだリモートの Emacs 上で行っていますが、音楽を再生しているのはローカルの Mac で動く iTunes です。
さて私はこのややこしい環境で「Emacs から iTunes を制御したい」と思いました。環境
であるところの Emacs ですから、当然 iTunes の操作程度はできなければいけないはずです。
実装
シェルから iTunes を操作できれば勝利確定だろうということは想像に難くないかと思います。で、その方法ですが、あるんですね、これが。
Mac には Apple Script
というものがありプロセス間通信で云々。osascript
というコマンドがあるのでこれにスクリプトを投げつければシェルから実行することができるのです。
さて、問題は Apple Script
の文法なのですが、これが「恐ろしく文脈依存で謎」でありまして、「だいたいそれっぽい英語を書くと動く」のであります(本当はそれなりにちゃんとした文法を持っているらしい)。場合によっては brainf*ck
よりも難解かと思われますし、読むのもさることながら書くのは非常につらいです(演算子の結合順序がよくわからん)。そしてその文法だけでなく、専用エディターであるところの Apple Script.app
の挙動もまた謎です(勝手に括弧が挿入されたり、括弧の位置が変わったりします)。
ということで苦労して書いたのがこちら。結局心が折れて最低限の機能しか実装していません。`itunes.applescript` とか名前をつけて保存しましょう
on run argv
tell application "iTunes"
set cmd to first item of argv
if cmd = "next" then
next track
else if cmd = "prev" then
previous track
else if cmd = "forward" then
fast forward
else if cmd = "back" then
back track
else if cmd = "rewind" then
rewind
else if cmd = "play" then
play
else if cmd = "toggle" then
playpause
else if cmd = "pause" then
pause
else if cmd = "stop" then
stop
else if cmd = "name" then
return name of current track
else if cmd = "artist" then
return artist of current track
else if cmd = "album" then
return album of current track
else if cmd = "count" then
return played count of current track
else if cmd = "playlist" then
return name of current playlist
else if cmd = "volup" then
set sound volume to sound volume + 5
else if cmd = "voldown" then
set sound volume to sound volume - 5
end if
end tell
end run
これを osascript
コマンドに食わせるとめでたく iTunes を制御できる、というわけです。ですからあとは nc
で待ち受けて、飛んできたコマンドを xargs
か何かでこれに投げればいいですね。(ポート番号はお好きに決めてください)
nc -k -l 5555 | xargs -n 1 osascript itunes.applescript
当然 Emacs は TCP/IP をしゃべれますから、設定ファイルにこんな感じの汚いコードを書きます(elisp な方、良い書き方教えてください)。
(defun itunes-call (command)
(let ((proc (open-network-stream "itunes" nil "MAC_HOST" 5555))) ; edit here
(process-send-string proc command)
(delete-process proc)))
(define-key global-map (kbd "C-c C-c")
(lambda () (interactive)
(itunes-call "toggle\n")))
(define-key global-map (kbd "C-c C-f")
(lambda () (interactive)
(itunes-call "next\n")))
(define-key global-map (kbd "C-c C-b")
(lambda () (interactive)
(itunes-call "back\n")))
(define-key global-map (kbd "C-c C-p")
(lambda () (interactive)
(itunes-call "volup\n")))
(define-key global-map (kbd "C-c C-n")
(lambda () (interactive)
(itunes-call "voldown\n")))
以上でサクッと望みを叶えることができました。もう Apple Script
書きたくないです。
まとめ
nc
+ oscscript
の組み合わせでいろいろリモートからコマンドを叩けるようにしているアプリはほかにもあるのですが、なんといっても Apple Script
を書くのがつらすぎます。つらいです。非常に。
次回は Emacs や OMake から Google Chrome
を操作して JavaScript によるフロントエンド開発を加速させるネタを書く予定です。予定ですが、いつになるかはわかりません。あしからず。
P.S.
ルーター自作のシリーズ、完全に停止していますが続編に期待している方がいらっしゃいましたらはてブにてお願いいたします。