Flickrの写真をExif併記でブログに貼るコードを生成するJavaScript for Automation

最近カメラを買ったのでそのことを書いたりしていた。

撮った写真を貼るときは、まず写真をFlickrにアップロードして、与えられたURLを元にコードを書くわけだけど、FlickrのURLにリンクしつつ、サムネイル的に縮小画像を貼りつけ、さらに一部のExif情報も一緒に載せたい。カメラやレンズに関する話を書いてるとき、そこに貼る写真については、それくらいやりたい。

これが、手動でやると相当メンドイし間違えたりするので、ツールを作ってみた。

ObjC.import('Cocoa');

var sys = Application("System Events");
sys.includeStandardAdditions = true;
var cmd = Application.currentApplication();
cmd.includeStandardAdditions = true;

var template =
    '|[$PHOTO_URL$:image=$THUMB_URL$:w512]||\n' +
    '|$CAMERA$, $LENS$<br>' +
    '$FOCAL_LENGTH$($FOCAL_LENGTH_IN35$), $EXPOSURE_TIME$, f$F_NUMBER$, ISO$ISO$||\n';

while(true){
    var url = sys.displayDialog(
        'Flickr URL',
        { defaultAnswer: 'https://www.flickr.com/photos/username/99999999999/' }
    ).textReturned;
    
    /^(.+\/photos\/.+?\/([0-9]+)\/)/.test(url);
    var photoUrl = RegExp.$1
    var photoId = RegExp.$2;
    var photoCurl = cmd.doShellScript('curl -L "' + photoUrl + '" | grep root.YUI_config.flickr.api.site_key ');
    /"(.+)"/.test(photoCurl);
    var apiKey = RegExp.$1;

    var apiUrl = 'https://api.flickr.com/services/rest?' + [
        'photo_id=' + photoId,
        'method=flickr.photos.getExif',
        'api_key=' + apiKey,
        'format=json'
    ].join('&');
    var apiCurl = cmd.doShellScript('curl -L "' + apiUrl + '"');

    /(\{.+\})/.test(apiCurl);
    var json = RegExp.$1;
    var data = JSON.parse(json);

    var map = {};
    map['PHOTO_URL'] = photoUrl;

    map['THUMB_URL'] = [
        'https://farm' + data.photo.farm + '.staticflickr.com',
        data.photo.server,
        data.photo.id + '_' + data.photo.secret + '_z.jpg'
    ].join('/');

    map['CAMERA'] = data.photo.camera;
    
    var exif = data.photo.exif;
    for(var i = 0; i < exif.length; i++){
        if(exif[i].tag == 'LensModel'){
            map['LENS'] = exif[i].raw._content;
        }
        if(exif[i].tag == 'FocalLength'){
            map['FOCAL_LENGTH'] = exif[i].clean._content.replace(/ /g, '');
        }
        if(exif[i].tag == 'FocalLengthIn35mmFormat'){
            map['FOCAL_LENGTH_IN35'] = exif[i].raw._content.replace(/ /g, '');
        }
        if(exif[i].tag == 'ExposureTime'){
            map['EXPOSURE_TIME'] = exif[i].raw._content;
        }
        if(exif[i].tag == 'FNumber'){
            map['F_NUMBER'] = parseFloat(exif[i].raw._content, 10).toString();
        }
        if(exif[i].tag == 'ISO'){
            map['ISO'] = exif[i].raw._content;
        }
    }
    var output = template.replace(/\$(.+?)\$/g, function(m, p1){
        return map[p1];
    });
    sys.displayDialog(output);
}

JavaScript for Automationで作ったので、Macスクリプトエディタにこのスクリプトをコピペして、アプリケーション形式で保存する。以後はそのappファイルを起動することで動作する。

使い方

起動するとURLを聞かれるので、そこにFlickrのURLを入力する。

そして3秒くらい待つと、ブログ貼り付け用のコードが出力される。

例えば、

https://www.flickr.com/photos/nacookan/31402730446/

こんなURLを入力したら、

|[https://www.flickr.com/photos/nacookan/31402730446/:image=https://farm6.staticflickr.com/5589/31402730446_08f21fb2a0_z.jpg:w512]||
|Sony ILCE-6500, E 35mm F1.8 OSS<br>35mm(52mm), 1/100, f3.5, ISO100||

こんなコードが生成される。

これを実際に貼り付けると、

https://www.flickr.com/photos/nacookan/31402730446/
Sony ILCE-6500, E 35mm F1.8 OSS
35mm(52mm), 1/100, f3.5, ISO100

こうなる。

はてなダイアリー用のコードが生成されるようになってる。他のブログとかに貼りたい人は、スクリプトの「var template =」ってなってる部分を自分が生成したい内容に合わせて書き換えればいい。

仕組み

まず入力されたURLの内容を取得して、そこに含まれるAPIアクセス用のキーを取り出す。

次に、そのキーも使ってExif取得APIのURLを組み立てて、その内容を取得。

APIJSONで返ってくるのでパースして、テンプレートに埋め込んで出力用の文字列を完成させる。

詳細

APIのキーは、いったん普通に写真ページにWebアクセスして返ってきたページの中から取りだしてる。これはたぶんログインが不要な一般アクセス用のものなのかな、よくわかんないけど。

今回は、非公開情報へのアクセスも、更新系の操作もなく、公開されてる写真に関する情報を取得するだけで、わざわざ登録ユーザーでログインしてキーを発行してもらう必要がなかったのでこうした。

Exif取得のAPIについても、普通に写真ページにWebアクセスするとAjaxで呼んでたので、それと同じものを呼んでる。Exifだけじゃなくサムネイルが格納されてるサーバーの情報とかも含まれていたので、縮小版のURLを組み立てるのも簡単だった。

手動で直したりもしている

実は、自分が使ったときは、これだけじゃ不十分だった。

カメラやレンズの名前が、Exifに記録されてる内容はわかりにくい。なのでそこだけ手動で書き換えてる。

例えば「Sony ILCE-6500」ではわかりにくいので「Sony α6500」にしたりしてる。まあしょうがないよね。