もやし日誌

日記のようなもの

Xamarin.MacでiTunesとSwinsianで再生している曲の情報を取得する

f:id:kazuki09:20180520153118p:plain AppleScriptを使った曲情報の取得のサンプルは探せばゴロゴロ出てきますが、アルバムアートの画像も含めてXamarin.Macから取得する方法が見つからなかったのでメモ。

転がってるSwiftを使ったサンプルを参考にどのAPIを叩けば曲情報が取れるのか調べる

NSDistributedNotificationCenterを使うとiTunesとSwinsianでの曲再生時にイベントが取れるようです。飛んできた通知の中に曲情報が入っているみたいなのでこれを利用します。

とりあえずSwinsianは公式HPにNSDistributedNotificationCenterで取ってくるべきNSNotificationのNameが書いてあるので、参考にSwiftのコードを書いてみました。

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        DistributedNotificationCenter.default().addObserver(self, selector: #selector(self.onTrackChange(notification:)), name: NSNotification.Name("com.swinsian.Swinsian-Track-Playing"), object: nil)
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
    
    @objc func onTrackChange(notification: NSNotification){
        print("Event recived.\n")
        let userinfo = notification.userInfo
        print(userinfo ?? "")
        print(userinfo?["thumbnailPath"] as? String ?? "")
        print("Event recived end.\n")
    }
}

f:id:kazuki09:20180520154732p:plain

曲情報が入ったAnyHashableが取れるみたいですね。ちなみにiTunesNSNotification.Nameの名前をcom.apple.iTunes.playerInfoに変更すればサムネイルのパス以外は取れます。

肝心のアルバムアートの取り方が分からない

Swinsianに関しては、pngのパスがAnyHashableに入ってるのでそこから取ってきてNSImageに突っ込めば表示できますね。簡単です。

しかし、iTunesに関してはScripting Bridgeを使って取得する必要があります。

Scripting Bridgeに関してはAppleのドキュメントを読めば大体わかると思いますが、要はWindowsでいうCOMみたいなものです。

developer.apple.com

ありがたいことにiTunes.hの生成の仕方が書いてあるので、書いてあるコマンドを打ってiTunes.hを生成しました。

sdef /Applications/iTunes.app | sdp -fh --basename iTunes

生成されたiTunes.hを読めば大方どのAPIを叩けばお目当てのアルバムアートが取れるかわかるはずです。

というわけでC#で書けばこんな感じになるはずです。(本当はSwift版も書こうかと思いましたが何故か上手く動かなかったのでやりませんでした)

var itunes = SBApplication.FromBundleIdentifier("com.apple.iTunes");
var ctrack = itunes.ValueForKey(new NSString("currentTrack"));
var front_artwork = ctrack.ValueForKey(new NSString("artworks")) as SBElementArray;
if (front_artwork.Count > 0)
{
    var aitem = front_artwork.Get()[0];
    var raw_image = aitem.ValueForKey(new NSString("rawData")) as NSData;
    var image = new NSImage(raw_image);
}

というわけでゴリ押しでコードを書く

gistb728c424cc574d02a29e841f19d2d534

あとがき

Xamarinとはいえ、こういったmacOS特有の機能を使う場合はまずはAppleのドキュメントを確認しなければなりませんし、大半のサンプルはSwift/ObjCで書かれているのでそれが読めないとかなりつらいです。