2014年2月16日日曜日

FlashAir 上の写真を一括ダウンロードして日付ディレクトリにアーカイブするシェルスクリプト作りました

昨年はいろいろあって後半はブログを更新できずじまいでしたが、最近自分と家族用に作ったシェルスクリプトを GitHub に公開 しましたのでそのご紹介をば。

どういったものかというと、下図のように FlashAir 上の写真を手元の Macintosh に一括ダウンロード (ただし既にダウンロード済のものはスキップ) し、それらを撮影日ごとに日付ディレクトリにアーカイブする、というシロモノです。撮影日情報は ExifTool で画像や動画ファイルの Exif ヘッダから取得してます。(無線アクセスポイントの切替を自動化したかった関係から、Macintosh 以外の OS では動作しません。すいません。)

追記: (2014/03/31) 先月やっと Mavericks にアップデートしたら、キーチェーン内の無線アクセスポイントのパスワードの属性情報の構成が変わってて上手く動作しなかったのでそちら修正しました。 v1.1 Release であれば Mavericks 対応しています。また、ターゲットとなるパスワードが保存されているキーチェーンの場所も「ログイン」から「ローカル項目」なる場所に変わっており、後者を CLI で参照するインターフェースはまだ提供されてません。そこはキーチェーンの管理ユーティリティで元の「ログイン」側にキーチェーンをコピーしてもらってから使う、というアドホックな対応になってます。

目次

セットアップや使い方など

利用に関しての必要最低限は GitHub:mo-ya/flashair-photos-sync で紹介してますので、そちらを参照ください。

こちらのブログではこれを作った背景や、作る時に勉強になった事などを書きたいと思います。

FlashAir についての感想

カメラとかその周辺デバイスとか全然詳しくなくて、FlahsAir も家族が買ってきたものです。そこでやっと FlashAir なるものがあることを知ったぐらいです。

その後ウェブで少し調べたんですが、ASCII.jp さんの記事 (だいぶ以前のものですが) が FlashAir について他製品 (Eye-fi とか) と比較しながら紹介してて勉強になりました。

いまさらながら、面白いアイディアだなと思いました。この手の機器って自分の頭の中で勝手にクライアント機器だろという思い込みがあったんですが、確かに写真を保存してるストレージ自身で無線アクセスポイント立てちゃえば出先でもどこでもスタンドアロンで動作できるんですよね。設定も他のアクセスポイント機器との関係を考えなくて済むのでシンプルで済みますし。

このスクリプトを作った理由

さて、じゃあなんでわざわざこんなもの作ったかといいますと、な話です。

FlashAir の紹介ページ を見ると以下の用途を想定しているようです。

  • 撮った写真をスマホやタブレットなど高解像度・大画面ですぐ見れる
  • 出先で撮った写真をその場でスマホなどでシェア
  • ↑ これらをするのにキャリア回線や Wifi アクセスポイント不要 (FlashAir 自身がアクセスポイントになるから)

これらの使い方はそれはそれで便利ですし良いんですが、うちの場合はこういった事もやりたいと思いまして。

  • カメラで撮った写真・動画は全部手元(PC やファイルサーバ)に保存
  • 撮影日情報を元に日付フォルダ分け
  • 保存した写真・動画は SD カードから消して OK

理由としては

  • わざわざ「どの写真を残すか」とか手動でフォルダ分けとかやってる時間がない
  • 保存用と考えると SD カードはサイズが小さいので、空き容量が無くなってきたら「どれ消そうか…」とか悩まずにばさっと消してしまいたい

といったことになるのかなと。そんなわけで以下の処理を自動化したツールを作ったというわけです。

  • FlashAir からの写真の一括ダウンロード (重複ダウンロードは行わずに)
    • FlashAir からのデータ転送速度は必ずしも早くないので、全写真のダウンロードを毎回やってると時間がかかりすぎます。なので、過去ダウンロードした写真はダウンロードしないようになってます。
  • 画像・動画ファイルの Exif ヘッダに記録されている撮影日でフォルダ分けして保存
    • これも毎度手でやってると面倒でそのうち止めちゃう→フォルダ内がカオスに、ってなことになりそうなので自動化しました。
  • 無線アクセスポイントの切替(例: 自宅 Wifi→FlashAir→自宅 Wifi)
    • FlashAir から写真をダウンロードしようとすると、当然自宅の Wifi から FlashAir に切り替えて戻すってのが必要なんですが、何度か手動でやってみたんですが意外に面倒で…。そんなわけでこの切替も自動化しました。これで写真データのダウンロードから PC (ファイルサーバでも OK) への保存までスクリプト実行一発で OK になりました。

ちなみに保存先は手元の PC とファイルサーバの両方に同時に保存できるようにしてあります。私の場合、前者は閲覧用、後者はバックアップと家族でのシェア用にしてます。

このスクリプトを作って変わったこと

このスクリプトのお陰で、日頃の生活での写真・動画の保存は以下の 2 アクションで済むようになりました。

  1. スクリプト実行

    $ flashair-photos-sync.sh -f -y
    
  2. カメラの電源オン (FlashAir を動作させるため)

後は待ってれば前回ダウンロード後に新たに撮られた写真・動画が勝手にダウンロードされて日付ディレクトリに保存 (ついでに iPhoto にも登録) してくれます。

写真を閲覧する時は Finder やプレビューよりも iPhoto の方が便利なので、フォルダごと iPhoto にインポートしてます。写真が入ってる日付フォルダがそのまま iPhoto の「アルバム」扱いになるので、iPhoto のアルバム管理も一石二鳥でできちゃってます。ちなみにスクリプト実行後に自動で iPhoto 登録する方法は GitHub:mo-ya/flashair-photos-syncPOST_SCRIPT の説明を参照下さい。

理想的には、ダウンロードと保存まで全部バックグラウンドでやってくれるのが望ましいんですけどね。まあ無線アクセスポイントが勝手に切り替わるタイミングができても嫌ですし、FlashAir の無線アクセスポイント立ち上げのためにカメラの電源入れる必要もありますんで、自動化できるのはここまでかなと考えてます。

勉強になったこと

Mac OS X の無線アクセスポイント切り替えについて

始めは CUI でどう無線アクセスポイント切り替えたら良いのか分からず、いろいろ調べました。

やっと見つけたのは networksetup(8) なるコマンドです。無線デバイスについての大抵の操作はできるようなんですが、このスクリプトで使ってるのは以下の 2 通りだけです。1 つ目が現在の Wifi ネットワークの SSID の表示、2 つ目が別の SSID への切り替えです。

$ networksetup -getairportnetwork <device>

$ networksetup -setairportnetwork <device>

これで切り替えはできるようになったんですが、どうも切り替えてすぐに写真ダウンロードしたり、ファイルサーバに接続しようとするとうまくいかず。

無線アクセスポイント切り替え後に IP アドレスなどのネットワークパラメータ割り当てを確認した後でもどうもうまくいかない場合があって何かと思ってたんですが、どうやらネットワークパラメータ割り当てた後に /etc/resolv.conf を更新してるようなんですね。

実際には /etc/resolv.conf/var/run/resolv.conf のシンボリックリンクになっており、後者が更新されます。このファイルはシステム環境設定の [ネットワーク] で指定した DNS サーバ等の情報が反映されるファイルなようで、DHCP にしている場合は DNS の情報が DHCP サーバから送られてきてから更新されるようです。

/etc/resolv.conf が読み込み可能になったことを確認してからの写真ダウンロード、ファイルサーバ接続はさっくりと上手くいくようになり、ここまで来てやっと無線アクセスポイント切り替えが自動化できました。

キーチェーンからのパスワード取得方法

もう一つ勉強になったのが、Mac OS X 標準のパスワード管理ユーティリティであるキーチェーンへの CUI でのアクセス方法についてです。

こちらも始めは「そもそもそんなことできるんだろか?」という感じでしたが、調べてみると security(1) なるコマンドでできることが。

無線アクセスポイントのパスワードにアクセスするのは以下のような感じです (これは Mountain Lion の場合。Mavericks は後述)。

$ security find-generic-password -g -s com.apple.network.wlan.ssid.<SSID>

具体的には以下のような出力です。実はパスワードは標準エラー出力に出ててちょっとはじめ戸惑いましたが、分かってしまえば簡単に扱えます。なお、パスワードを表示する前には下記の 2 つのウィンドウのどちらかが表示され、[許可] をクリックするか、管理者の名前とパスワードを入力する必要があります (この 2 つの違いは後述)。

$ security find-generic-password -g -s com.apple.network.wlan.ssid.flashair

許可すると以下のようにキーチェーンに登録されている各種情報とパスワードが表示されます。

keychain: "/Users/user/Library/Keychains/login.keychain"
class: "genp"
attributes:
    0x00000007 <blob>="flashair"
                 :
    "acct"<blob>="AirPort"
                 :
    "desc"<blob>="AirPort network password"
                 :
    "svce"<blob>="com.apple.network.wlan.ssid.flashair"
    "type"<uint32>=<NULL>
password: XXXXXXXX            ← これだけは標準エラー出力に出るので注意

dump-keychain オプションを使えば、パスワード以外の情報一式を抜き出せます。無線アクセスポイントのパスワードとして何を保存しているか一覧を見たいなら以下のように。

$ security dump-keychain | grep com.apple.network.wlan.ssid.

    "svce"<blob>="com.apple.network.wlan.ssid.flashair"
    "svce"<blob>="com.apple.network.wlan.ssid.homewifi"    
                      :

追記: なお、Mavericks だと無線アクセスポイントのパスワードを管理するキーチェーン内の属性情報の持ち方が変わっているため、以下のように問い合わせる必要があります。

$ security find-generic-password -g -s AirPort -a flashair

keychain: "/Users/user/Library/Keychains/login.keychain"
class: "genp"
attributes:
    0x00000007 <blob>="flashair"
                 :
    "acct"<blob>="flashair"
                 :
    "desc"<blob>="AirPort network password"
                 :
    "svce"<blob>="AirPort"
    "type"<uint32>=<NULL>

ちなみに、ファイルサーバへの接続パスワードはこのような感じで取り出せます。 (こちらは Mountain Lion、Mavericks ともに違いありません)

$ security find-internet-password -g -s <サーバ名> -r "<プロトコル> "

具体例はこちら。

$ security find-internet-password -g -s 192.168.1.10 -r "smb "

keychain: "/Users/user/Library/Keychains/login.keychain"
class: "inet"
attributes:
    0x00000007 <blob>="192.168.1.10"
    0x00000008 <blob>=<NULL>
    "acct"<blob>="user"
                :
    "ptcl"<uint32>="smb "
    "srvr"<blob>="192.168.1.10"
    "type"<uint32>=<NULL>

security(1) を見つける前は、独自でどっかにパスワード保存するしかないかなぁと思ってましたが、キーチェーンから取り出すという筋の良い形にできてラッキーでした。

ログインキーチェーンとシステムキーチェーンの違い

キーチェーン内のパスワードにアクセスする際、[許可] をクリックするか、管理者の名前とパスワードを入力するかしなければならないと書きましたが、どちらになるかは対象のパスワードが ログインキーチェーンシステムキーチェーン のどちらに保存されているかによります。

これはアプリケーションフォルダの下のユーティリティフォルダ内の [キーチェーンアクセス] ユーティリティを呼び出してみるとどちらに何が登録されているかひと目で分かります。

ログインキーチェーンはユーザレベルで管理できるものであるため、特にパスワード入力の必要なくアクセス許可できる上、[常に許可] といったことも可能です。一方でシステムキーチェーンはアクセスの際に管理者のユーザ名とパスワードの入力が求められ、[常に許可] といったこともできません。

ただ、システムキーチェーンに入っているパスワードをログインキーチェーンに移動するのは意外と簡単です。やり方は以下の通りです。

  1. アプリケーションフォルダの下のユーティリティフォルダ内の [キーチェーンアクセス] でキーチェーンの管理ユーティリティを呼び出す
  2. 左上ペインで [システム] を選択
  3. システムキーチェーンに管理されており、ログインキーチェーンに移動したいパスワードを選択して Ctrl-C
  4. 左上ペインで [ログイン] を選択し、Ctrl-V

とりあえずこれでログインキーチェーンにもパスワードが登録されたので、security(1) によるアクセス時にいちいちパスワードを入力する必要はなくなります。

ただ、キーチェーンはときおり壊れる (?) らしく、あまりあれこれいじらない方が良いようです。私の手元でも (普段使わないので困ってはいませんが) アクセスできない項目があったりします…。

追記: Mavericks だとキーチェーンの種別に ローカル項目 というものが増えています。想像ですが、おそらく iCloud キーチェーンに絡むものではないかなと。2014/03/31 現在、手元の security(1) コマンドではこのキーチェーンにはアクセスができていません。少しウェブ上も調べましたが、やはり CLI でこのローカル項目にアクセスする方法は提供されていないようです。そのうちローカル項目や iCloud キーチェーンに CLI でアクセスできるインターフェースが提供されると助かるのですが…。

キーチェーンへのアクセスの「常に許可」を辞めたいときには?

余談ですが、一度 security(1) によるアクセスを [常に許可] にして、その後やっぱり許可を止めたい場合には以下のようにします。

  1. [キーチェーンアクセス] ユーティリティを呼び出す
  2. 該当の項目をダブルクリックし詳細情報を表示
  3. [アクセス制御] をクリック
  4. [これらアプリケーションによるアクセスを常に許可] という場所にアプリケーションのリストが表示される。一度 security(1) に [常に許可] を出している場合は、以下のように security がリストに含まれているはず
  5. security を選択して、下の 「ー」をクリック
  6. 右下の [変更内容を保存] をクリック

これで、再度 security(1) で呼び出した場合は、また許可を促すウィンドウが出てくるようになります。

おわりに

さて、今回自宅用に作ったスクリプトをそれっぽい感じで公開したので、ちょっと「へー」と思ったことなどブログにまとめてみました。

使える環境が結構限られてるのでどーなのかなとは思いましたが、お役に立てば幸いです。いい加減 OS も Mavericks に上げなきゃと思ってるので、そちらも動作確認したら追記します。

追記: Mavericks にアップデートしたら、色々変わってて慌てて修正しました(汗)。ブログの更新はさらに 1 ヶ月かかってしまいましたが…。まだ私は iCloud キーチェーン使ってませんが、使いはじめるとまた手直ししなきゃいけないかもしれませんね ^^;

でわでわ

0 件のコメント:

コメントを投稿