2010年1月24日日曜日

メモ: オリジナルの Automator アクションを作る

Mac OS X 10.6 では、Xcode 3.2 を使います。Mac OS X 10.6 から AppleScript Studio が deprecated になり、AppleScriptObjC を使うことになりました。簡単に言うと、AppleScript で Objective-C のクラスを書けるように、うまいこと対応を付けたものです。これによって、Automator の実行速度が上がったり、ユーザにとってはいいことずくめですが、問題は、今までの Automator アクションの作り方と大幅に変わってしまったことです。現時点では Google 先生が教えてくれる情報は、あまりアテになりません。Apple もドキュメンテーションをサボっていて、手探り状態です。

まず、知っておかないといけないのは、Xcode 3.2 が作ったテンプレートの違いです。Mac OS X 10.5 用のアクションは、以下のように、単に run ハンドラに input と parameters が渡されるだけでした。

on run {input, parameters}
  -- Add your code here, returning the data to be passed to the next action.

 return input
 
end run

これからは、myaction.script にはこんなコードが生成されます。

script myaction
 property parent : class "AMBundleAction"

 on runWithInput_fromAction_error_(input, anAction, errorRef)
  -- Add your code here, returning the data to be passed to the next action.

  return input
 end runWithInput_fromAction_error_
end script

script 〜 end script は見慣れないブロックです。これは、Objective-C のクラス定義で、myaction というクラスを宣言しています。2行目の property parent の行は AMBundleAction を継承をしていることを宣言しています。これにより、NSObject → AMActionAMAppleScriptActionAMBundleAction → myaction という継承ツリーを持ちます。on runWithInput_fromAction_error_ 〜 end runWithInput_fromAction_error_ はメソッドの定義です。オリジナルのアクションは、runWithInput:fromAction:error: をオーバーライドして作るという形になります。

AppleScript しか知らなくて、ピンと来ない人は、まずは、以下のようにテンプレートを埋めましょう。

script myaction
 property parent : class "AMBundleAction"
 
 on runWithInput_fromAction_error_(input, anAction, errorRef)
  -- Add your code here, returning the data to be passed to the next action.
  set input to input as list
  set output to {}
  repeat with i in input

   -- do something for i

  end repeat
  return output
 end runWithInput_fromAction_error_
 
end script

これで、入力ファイルに対して、順番に何かをする、という処理が書けると思います。アクションの出力は、ここではファイルと仮定しますが、POSIX File の文字列を output のリストに詰め込んで返却すれば OK です。

パラメタの参照

パラメタは以前は run ハンドラの引数に渡されていました。これからは、AMBundleAction から継承した parameters() メソッドを使って、パラメタの値が入ったレコードを取得します。個々のパラメタには AMDefaultParameters (Info.plist にあります) に設定したキーでアクセスできます。例えば、foo というキーを持つパラメタは foo of parameters() でアクセスできます。ただし、取得した値は、as text や as number などで、型をきっちり指定してください。パラメタと GUI のバインディングなどは、これまでと同じなので省略します。

アクションのバンドル

アクションのバンドルの中のファイル (リソース) の参照には path to resource は使えません。これだと Automator.app のバンドルを参照してしまいます。AMBundleAction から継承した bundle() メソッドを使って、一旦 NSBundle オブジェクトを取得したあと、NSBundle のメソッドを使ってアクセスします。名前の衝突を防ぐために、縦棒 (|) で囲って |bundle|() とやるとアクションのバンドルオブジェクトが取得できますので、それに対して、pathForResource:ofType:等を使ってリソースのパスを取得します。具体的には、以下のようになります。

set action_bundle to |bundle|()
set aPath to action_bundle's pathForResource_ofType_("image", "tiff")

エラーの返却方法などは、まだよく分かっていません。この辺になにやら書いてありますが、NSNumber と NSString を NSArray に突っ込んで返してるけど、NSError を返却するんじゃないの? という疑問が…。この情報も古いのかもしれません…。

2010年1月18日月曜日

Automator 雑感

サービスの作成プリントプラグインの作成ワークフローの作成、そしてGUI 付きのオリジナルのアクションの作成と、Automator を一通り使ってみました。

Automator が登場した当初、GUI で操作できるのは良いのですが「どうせおもちゃしか作れないんでしょ?」「オリジナルのアクションが作れるかもしれないけど、本当にしたいことは、Objective-C で書かないといけないんでしょ?」と思っていました。これは誤りでした。一通り使ってみた現在では、生産効率の高いソフトウェアプラットホームとして、十分使えるというのが認識です。「AppleScript を実行」や「シェルスクリプトを実行」で使い捨てで書けますし、必要に応じて GUI 付きのアクションに仕立てて、再利用することもできます。

これからも積極的に Automator を使っていきますよー!

2010年1月17日日曜日

サブフォルダを再帰的に辿って、ファイルにナントカする

指定したフォルダに含まれるすべてのファイル (サブフォルダも含む) に対して、何かを行うというのはよくありますが、AppleScript で書くと、意外と面倒だったりします。

Automator なら一発です。

最初に指定するテンプレートは、「ワークフロー」です。ワークフローは、Automator を起動して、実行ボタンを押して動かします。

空のワークフローに、以下のアクションを追加します。

  • 「指定された Finder 項目を取得」アクションは、選択している GUI でファイルやフォルダを選択し、そのリストを次のアクションへ渡します。上の例では、2つのフォルダを選択しています。※
  • 「フォルダの内容を取得」アクションは、受け取ったフォルダに含まれるファイルやフォルダの一覧を取得します。ここでは、サブフォルダに含まれるファイルやフォルダも再帰的に取得してほしいので、「見つかったサブフォルダからも取得」にチェックを入れておきます。
  • 「Finder 項目にフィルタを適用」アクションは、受け取ったファイルやフォルダの一覧を、指定した条件でフィルタリングします。上の例では、拡張子とファイル名の 2つの条件を追加しています。「結果」ボタンを押して、何がヒットしたかを表示させています。4つのファイルのリストが次のアクションに渡されます。
  • 最後に AppleScript で実際に何をするかを書きます。input には、ファイルのリストが渡されます。parameter は、とりあえず無視で OK です。もし、この後、別のアクションを実行したいなら、run ハンドラで次のアクションに渡すデータ (ファイルのリストや、文字列) を返却してください。

AppleScript が使える人は、今日から Automator で幸せになれますよ。シェルスクリプト、Perl、Ruby、Python でも同様に書けます。

※ サービスやアプリケーション (ドロップレット) の形で作ると、ユーザによって起動時にフォルダが指定されますので、この部分は不要になります。

2010年1月14日木曜日

PDF を Web Receipts フォルダに保存

Automator のお題をもう一つ。今度はプリントプラグインです。プリントプラグインとは、印刷ダイアログの左下にある「PDF ▼」で実行するワークフローです。このワークフローは、プリントシステムから PDF ファイルを受け取り、それに対する処理を行うものです。

プリントプラグインは、かつて PDF ワークフローと呼ばれていたようで、Mac OS X 10.6 に付属の「PDF を Web Receipts フォルダに保存」は現在のプリントプラグインとは違う形式で作られています。これをプリントプラグインで作り直してみます。ただ作り直すだけではつまらないので、Web Receipts フォルダに印刷を実行した日の日付のフォルダを作って、その中に PDF ファイルを保存する仕様に変更します。

Automator で、プリントプラグインのテンプレートを使い、「シェルスクリプトを実行」のアクションで、以下の Python スクリプトを実行させます (ポップアップのシェルを /usr/bin/python にする) 。

オリジナルの「PDF を Web Receipts フォルダに保存」の実体は Python で書かれています。これが、同じファイル名で上書きしないなど、色々気を遣ってよくできているので、これをパクって作ります。PDF ワークフローとは異なり、ファイル名が渡されるだけですので、安全なファイル名に変換するルーチンは削除してあります (/tmp に保存されているのだから、既に安全なファイル名のはず) 。適当に手直ししてますが、清野は Python を使ったことがないので、変なことを書いているかもしれません。

#!/usr/bin/python
#
# This script is stolen from
# /Library/PDF Services/Save PDF to Web Receipts Folder.pdfworkflow/Contents/tool

import os
import shutil
import sys
import time

def main(argv):
    (title, ext) = os.path.splitext(os.path.basename(argv[0]))
    pdfFile = argv[0]

    today = time.strftime("%Y-%m-%d", time.localtime())
    destDirectory = os.path.expanduser("~/Documents/Web Receipts/" + today + "/")

    # Create the Web Receipts folder if necessary.
    try:
        os.makedirs(destDirectory)
    except:
        pass
    
    # Build a file path pointing into the web reciepts folder
    # using the document's title and a PDF extension.
    destFile = title + ".pdf"
    destPath = os.path.join(destDirectory, destFile)

    # If the filename we want is already in use then start
    # appending numbers until we get a unique name.
    i = 2
    while (os.path.exists(destPath)):
        destFile = title + "." + str(i) +".pdf"
        destPath = os.path.join(destDirectory, destFile)
        i = i + 1

    # Move the file if possible otherwise copy it.
    shutil.move(pdfFile, destPath)

if __name__ == "__main__":
    main(sys.argv[1:])

これを、~/Library/PDF Services/ に保存します。Automator の画面は、以下のようになります。

清野は、Files lite との同期用スクリプトを少しいじって、Web Receipts フォルダの内容を iPod touch へ転送するようにしています。ちょっと気になった Web ページなどを保存しておき、後で iPod touch でゆっくり読むためです。

2010年1月13日水曜日

エンコードスクリプトをサービスにしてみる

動画をエンコードするのに Terminal を起動するのが面倒なので、Automator を使ってサービスにしてみます (Mac OS X 10.6 以上) 。

サービスにすると、このように、コンテストメニューから呼び出せます。便利便利。

手順1

Automator を起動し、サービスのテンプレートを選びます。テンプレートに沿って空のワークフローが作成されます。

手順2

ウィンドウ上部のサービスは、次の選択項目を受け取ります:のポップアップからムービーファイルを、検索対象:からすべてのアプリケーションを選択します。

手順3

左側のライブラリから、ユーティリティを選びます。次に、その隣のカラムに出てきたシェルスクリプトを実行を、右の広いエリアにドラッグ&ドロップします。

シェル:のポップアップから/bin/shを、入力の引き渡し方法:から引数としてを選択します。

以下のスクリプト書きます。

VLC=/Applications/VLC.app/Contents/MacOS/VLC
SIZE="width=480,height=270"
ASPECT="canvas-aspect=1:1"
FPS="fps=29.97"
CROPPADD="cropbottom=2,paddtop=2,paddbottom=2"
X264_OPTS="profile=baseline,level=30,keyint=30,bframes=0,ref=1,nocabac"
VIDEO="venc=x264{$X264_OPTS},vcode=h264,vb=1280"
AUDIO="acodec=mp4a,ab=128"
OPTS="deinterlace,audio-sync"
MUX="mux=mp4"

while [ $# -gt 0 ] ;
do
 FN=`basename "$1" .mpg`.mp4
 DIR=`dirname "$1"`
 cd "$DIR"
 $VLC --intf=dummy \
      --sout="#transcode{$SIZE,$FPS,$ASPECT,vfilter=croppadd{$CROPPADD},$VIDEO,$AUDIO,$OPTS}:standard{$MUX,dst='$FN',access=file}" \
      "$1" \
      vlc://quit > /dev/null 2> /dev/null
 shift
done

手順4

ワークフローを保存します。通常は ~/Library/Services/ に保存します。完成すると、以下のような画面になっているはずです。

複数のムービーファイルを選択して、サービスを実行してもちゃんとエンコードされます。

実際に作業をするとお気づきになると思いますが、Perl や Ruby などでもスクリプトを書けます。色々な用途に使えそうな Automator 。侮れません。

blogspot で自作したワークフローファイルとかを配布したいのですが、どのようにしたらいいのでしょうか??? よい、知恵をお持ちの方、コメントを付けてください。

2010年1月10日日曜日

iPod touch 導入一周年

もういつだったか忘れてしまったのですが、iPod touch を手にして、そろそろ一年が経ちます。その間、何が変わったかを振り返ってみたいと思います。画像は、私の iPod touch のスクリーンショットです。

iPod touch の購入にあたり、通勤時間を有効に使うというテーマを設定しました。自宅や職場でしている作業が iPod touch によって通勤電車の中でできるようになれば、成功したと言えます。そうした観点から、今使っているアプリを紹介します。

メール

iPod touch 導入後しばらくして、MacBook Air で読むメールアドレスと、iPod touch で読むメールアドレスを完全に分離しました。職場で読むメールと、通勤電車の中で読むメールを分離するためです。Dock の Mail.app に出ている未読メール数は仕事中でも気になるもので、これは予想以上に効きました。今後もこの方針で行きます。

Byline (450円)

RSS リーダの決定版。画像も含めてオフラインで読めるというのがうれしいです。RSS での情報収集は極めて有用ですが、案外時間を取ってしまうものです。Safari のブックマークバーから RSS のエントリを取り除いたことで、メール同様にすっきりしました。この方針も堅持します。

Todo (1,200円)

通勤電車の中で、その日やることを整理しています。だいたい、アイデアは TODO 項目に関連が付くもので、ふと思いついたら TODO 項目を作って、そこに書きます。MacBook Air の画面が狭いので、iCal には TODOリストを表示せず、iPod touch だけで管理することで、画面を広く使うという副次的な効果もありました。iPod touch を用途限定のサブディスプレイとして使うというのは結構イケます。ちょっと高いアプリですが、今では必須です。

Files lite (無料)

PDF ビューワーとして使っています。MacBook Air との同期には sitecopyを使っています。ケータイの PDF ビューワーと違って、高速かつ精彩に出るので、かなりのドキュメントが読めます。ちょっと変わったところでは、コンビニの払込票のバーコードを表示して、読み込んでもらったことがあります。ちゃんと読めるのに驚きました。

ビデオ

録画した番組を見るのに使っています。このための方法は色々調べて、他のエントリなどで書きました。予約録画後、編集、エンコード、同期といった手間が必要なので、その部分を自動化できればもっといいのですが…。

これだけやることがあると、通勤時間の方が足りなかったりします…。