Exif情報を元にJPEGファイル名をリネームするJavaScript for Automation

追記

スクリプトは、2016年に修正してます。

追記ここまで。


OS X 10.10 Yosemiteの新機能で、「JavaScript for Automation」というのがある。

これは、Macスクリプトからコントロールできる仕組みが、AppleScriptの代わりにJavaScriptで書けるようになったということ。

AppleScriptは文法や構造が異様に難しいっていうか独特で、見よう見まねで書くのが精一杯って感じなんだけど、そこがJavaScriptで書けるのは熱い。熱すぎる。

ってことでちょっとサンプル的に自分が欲しいと思ってたスクリプトを書いてみた。

JPEGのファイル名を、Exif情報を元にリネームするスクリプト

iPhoneやデジカメで撮った写真のファイル名が、

img_20141024_012345_Apple_iPhone6_1.jpg

こんな感じになるスクリプト

「img + 年月日 + 時分秒 + カメラメーカー名 + カメラ名 + 連番 + .jpg」っていうルールでリネームする。連番は、カメラで連写などして年月日時分秒まで一致した場合にカウントアップする。

複数のカメラで撮った写真をひとつのフォルダにまとめて保存し、さらにレタッチしてファイルのタイムスタンプが変化してる場合などに、こういう風にファイル名がついていれば整理しやすい。

以前はRubyで書いてたんだけど、いちいちターミナルからスクリプトを実行するのが面倒だった(そうじゃなくする方法があるのももちろん知ってるけど)。

コード

ソースコードは以下。

function openDocuments(docs) {
    var app = Application.currentApplication();
    app.includeStandardAdditions = true;
    
    var count = 0;
    for(var i = 0; i < docs.length; i++){
        var src = docs[i].toString();
        if(!/\.jpe?g$/i.test(src)) continue;
        
        // Get Exif
        var sips = app.doShellScript('sips -g all "' + src + '"');
        var lines = sips.split(/\r\n|\r|\n/).slice(1);
        var exif = {};
        for(var j = 0; j < lines.length; j++){
            /^\s*([^:]+): (.+)$/.test(lines[j]);
            exif[RegExp.$1] = RegExp.$2;
        }
        
        // Generate Name
        var parent = src.replace(/[^\/]+$/, '');
        var dst;
        var index = 1;
        while(true){
            dst =
                parent +
                'img_' +
                exif.creation.replace(/:/g, '').replace(/ /, '_') + '_' +
                exif.make.replace(/[^a-z0-9-]/ig, '') + '_' +
                exif.model.replace(/[^a-z0-9-]/ig, '') + '_' +
                index.toString() +
                '.jpg';
            var ret = app.doShellScript('if test -e "' + dst + '"; then echo 1; else echo 0; fi');
            if(ret == '0') break;
            index++;
        }
        
        // Rename
        app.doShellScript('mv "' + src + '" "' + dst + '"');
        count++;
    }
    
    app.displayAlert(count.toString() + ' file' + (2 <= count ? 's' : '') + ' renamed.');
}

Yosemiteで、スクリプトエディタ(以前の「AppleScriptエディタ」から改名になった)を起動して、上記コードをコピペし、適当な場所に適当な名前でアプリケーション形式(.app)で保存する。

あとはそのappファイルに対してJPEGファイルをドラッグ&ドロップするとリネームされる。複数のファイルをドロップしてもOK。

ポイント

  • ファイルをドロップして起動するようなスクリプトは、function openDocuments(docs) {...} で書く。
    • この名前の関数を定義しておくと、勝手に呼ばれるということ。
    • そしてdocsにドロップしたファイルのPathが配列で入ってる。
  • app.doShellScript(...) で外部コマンドを実行できる。
    • sipsExifの内容を取り出したり、testでファイルの存在チェックをしたり、mvでファイルをリネームしたりしている。
  • app.displayAlert(...) でメッセージダイアログが出せる。

あとは皆さんご存じのJavaScriptで書ける。正規表現リテラルRegExpオブジェクトもある。

JavaScript for Automationでファイルの操作をする方法(Windowsで言うところのFileSystemObject的なやつ)がわからなかったのでシェルコマンドを呼び出してる。なんか方法あるのかな。

いいね

今までは、慣れないAppleScriptで超がんばって書くか、あきらめてRubyで書いてターミナル上で使うかっていう感じだった(jscっていうターミナルで動くJavaScriptのエンジンもあるけど使ってなかった)けど、JavaScript for Automationはすごくいい。app形式にできて、GUIも制御できて、シェルコマンドも呼べる。それでいて言語的にはよく知ってるJavaScript。すばらしい。

ただこの「JavaScript for Automation」っていう名前が微妙だなあ。なんか呼びづらいし、OS Xの機能だっていうことが伝わりにくい。いい案は思い浮かばないけど。