エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

iTunes の CD の情報を JavaScript で設定する

CD を購入した時に、iTunes 上で情報を設定するのが面倒だったのでスクリプトでなんとかしようと思ったらなんとかなったので、そのメモ。

従来から AppleScriptiTunes を操作することはできましたが、AppleScript は不得意なため Yosemite から使えるようになった JavaScript を利用しています。
加えて、CoffeeScriptコンパイル結果をコンソールに出力して、パイプで流し込んでやれば CoffeeScript でもやりたいことができるので、最終的には CoffeeScript で書いています。


情報の取得方法と設定方法を確かめる

まずは osascript の interaction mode で一つずつ動作を確認してます。

osascript を interactive mode で言語に JavaScript を指定して起動します。

$ osascript -l JavaScript  -i
>>


iTunes のオブジェクトを取得します。

>> itunes = Application('iTunes')
=> Application("iTunes")


iTunes アプリケーションは sources という要素を持っています。
どのような要素を持っているかはスクリプトエディタの用語説明で閲覧することができます。用語説明の開き方は後ろの方で書きます。

>> itunes.sources()
=> [Application("iTunes").sources.byId(64), Application("iTunes").sources.byId(25404), Application("iTunes").sources.byId(145406)]


sources は クラス Source の集まりで、Source には kind というプロパティがあります。kind の値を表示させてみると audio CD となっているものがあります。この source が CD です。

>> for(var source of itunes.sources()) { console.log(source.kind()); }
library
radio tuner
audio CD
=> undefined
>> itunes.sources[2].kind()
=> "audio CD"


同様に Source は クラス Playlist の集まりである playlists という要素を持っています。通常は数は1つのようです。

>> itunes.sources[2].playlists()
=> [Application("iTunes").sources.byId(145804).audioCDPlaylists.byId(145805)]
>> itunes.sources[2].playlists[0]()
=> Application("iTunes").sources.byId(145804).audioCDPlaylists.byId(145805)


同様に Playlist は クラス Track の集まりである tracks という要素を持っています。tracks の各要素が CD のトラック情報になります。

>> itunes.sources[2].playlists[0].tracks()
=> [Application("iTunes").sources.byId(145804).audioCDPlaylists.byId(145805).audioCDTracks.byId(145812),  (...以下、トラックの数だけオブジェクトが並ぶ...)]


Track には name というプロパティがあります。これがトラックの名前です。

>> for(var track of itunes.sources[2].playlists[0].tracks()) { console.log(track.name()); }
(...CD の全トラックの名前が並ぶ...)


プロパティに値を代入することで設定をすることができます。
この辺り、一般的な JavaScript と記述の方法が違いますので注意してください(実態は JavaScript にマップされた AppleScript のらしい)。

itunes.sources[2].playlists[0].tracks[0].name = 'This Will Be the Day'

CoffeeScript で情報を一覧する

CD のトラック情報を一覧する CoffeeScript です。

itunes = Application('iTunes')

for source, source_index in itunes.sources()
  continue if source.kind() != 'audio CD'
  for playlist, palylistIndex in source.playlists()
    console.log """
      PLAYLIST #{palylistIndex}

      duration:    #{playlist.duration()} sec
      name:        #{playlist.name()}
      loved:       #{playlist.loved()}
      shuffle:     #{playlist.shuffle()}
      size:        #{playlist.size()} byts
      songRepeat:  #{playlist.songRepeat()}
      specialKind: #{playlist.specialKind()}
      time:        #{playlist.time()}
      visible:     #{playlist.visible()}
    """

    for track, trackIndex in playlist.tracks()
      console.log """

        TRACK #{trackIndex}

        album:            #{track.album()}
        albumArtist:      #{track.albumArtist()}
        albumLoved:       #{track.albumLoved()}
        albumRating:      #{track.albumRating()}
        albumRatingKind:  #{track.albumRatingKind()}
        artist:           #{track.artist()}
        bitRate:          #{track.bitRate()}
        bookmark:         #{track.bookmark()}
        bookmarkable:     #{track.bookmarkable()}
        bpm:              #{track.bpm()}
        category:         #{track.category()}
        comment:          #{track.comment()}
        compilation:      #{track.compilation()}
        composer:         #{track.composer()}
        databaseID:       #{track.databaseID()}
        dateAdded:        #{track.dateAdded()}
        description:      #{track.description()}
        discCount:        #{track.discCount()}
        discNumber:       #{track.discNumber()}
        duration:         #{track.duration()}
        enabled:          #{track.enabled()}
        episodeID:        #{track.episodeID()}
        episodeNumber:    #{track.episodeNumber()}
        eq:               #{track.eq()}
        finish:           #{track.finish()}
        gapless:          #{track.gapless()}
        genre:            #{track.genre()}
        grouping:         #{track.grouping()}
        itunesu:          #{track.itunesu()}
        kind:             #{track.kind()}
        longDescription:  #{track.longDescription()}
        loved:            #{track.loved()}
        lyrics:           #{track.lyrics()}
        modificationDate: #{track.modificationDate()}
        playedCount:      #{track.playedCount()}
        playedDate:       #{track.playedDate()}
        podcast:          #{track.podcast()}
        rating:           #{track.rating()}
        ratingKind:       #{track.ratingKind()}
        releaseDate:      #{track.releaseDate()}
        sampleRate:       #{track.sampleRate()}
        seasonNumber:     #{track.seasonNumber()}
        shufflable:       #{track.shufflable()}
        skippedCount:     #{track.skippedCount()}
        skippedDate:      #{track.skippedDate()}
        show:             #{track.show()}
        sortAlbum:        #{track.sortAlbum()}
        sortArtist:       #{track.sortArtist()}
        sortAlbumArtist:  #{track.sortAlbumArtist()}
        sortName:         #{track.sortName()}
        sortComposer:     #{track.sortComposer()}
        sortShow:         #{track.sortShow()}
        size:             #{track.size()}
        start:            #{track.start()}
        time:             #{track.time()}
        trackCount:       #{track.trackCount()}
        trackNumber:      #{track.trackNumber()}
        unplayed:         #{track.unplayed()}
        videoKind:        #{track.videoKind()}
        volumeAdjustment: #{track.volumeAdjustment()}
        year:             #{track.year()}
      """


これを例えば cd-info.coffee というファイル名に保存し、coffee コマンドでコンパイルした結果を osascript にパイプで流し込むとスクリプトが実行されます。

$ coffee -p -c cd-info.coffee | osascript -l JavaScript

用語説明を開く

まずスクリプトエディタを起動します。
スクリプトエディタのファイルメニューから用語説明を開くを選択します。


開いたダイアログから iTunes を選択して選択ボタンを押します。


擁護説明のウィンドウが開きます。ただし開いた直後の状態では AppleScript での説明になっているので言語を変更します。


ウィンドウの上部にあるリストで言語を AppleScript から JavaScript に変更します。


ウィンドウの表示が JavaScript のものになります。


いつか読むはずっと読まない:The Custard Protocol

前作のソフロニアの時代から大きく下ってアレクシアの娘、プルーデンスの物語へ。

…ってソフロニアの物語の訳本の最終巻がまだ出てないんですけれど。

プルーデンス女史、印度茶会事件を解決する (続・英国パラソル奇譚)

プルーデンス女史、印度茶会事件を解決する (続・英国パラソル奇譚)