Archive for 7月, 2010

2010/07/31 InDesign CS3で、指定ScriptLabelの中のテキストの、指定行の指定文字以降を行末まで取得

InDesign CS3で、現在オープン中の最前面のドキュメント上の指定のScript Labelがついているtext frame中のテキストで、指定行目の指定文字以降の文字を行末まで取得するAppleScriptです。

「指定文字」が存在しなかった場合には行ごと返します。

id1.jpg

スクリプト名:InDesign CS3で、指定ScriptLabelの中のテキストの、指定行の指定文字以降を行末まで取得
set aRes to getLabeledDataAndPickUp("hiyokoMaker", 2, "/") of me
–> "ボボ・ブラジル"

set aRes to getLabeledDataAndPickUp("hiyokoMaker", 2, "ぴよぴよ") of me
–> "■ひよこの原産地/ボボ・ブラジル"

–指定ScriptLabelの中のテキストの、指定行の指定文字以降を行末まで取得
on getLabeledDataAndPickUp(aScriptLabel, aLineNum, aMarker)
  set aRes to retLabeledData(aScriptLabel) of me
  
set aList to paragraphs of aRes
  
set aLine to contents of item aLineNum of aList
  
set aPos to offset of aMarker in aLine
  
set aText to text (aPos + 1) thru -1 of aLine
  
return aText
end getLabeledDataAndPickUp

–指定のScript Labelのデータ(Contents)を取り出す
on retLabeledData(aScriptLabel)
  tell application "Adobe InDesign CS3"
    tell document 1
      try
        set aObj to every page item whose label is aScriptLabel
        
        
set targObj to first item of aObj
        
set aRes to contents of text 1 of targObj
      on error
        return "<error>"
      end try
    end tell
  end tell
end retLabeledData

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/31 現在のドキュメント上のアイテムをすべてグループ解除

InDesign CS3で、現在オープン中の最前面のドキュメント上のオブジェクトをすべてグループ解除するAppleScriptです。

スクリプト名:現在のドキュメント上のアイテムをすべてグループ解除
ungroupAll() of me

on ungroupAll()
  tell application "Adobe InDesign CS3"
    tell document 1
      tell every page
        repeat
          set gList to every group
          
if gList = {} then exit repeat
          
tell every group to ungroup
        end repeat
      end tell
    end tell
  end tell
end ungroupAll

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/31 リーダー罫文字のあとの文字を取得する

与えられた文字列のうち、リーダー罫として指定した文字(連続する「…」文字など)のあとに出現する文字を返すAppleScriptです。リーダー罫が文字列中に存在しなかった場合にはそのまま返します。

InDesignの書類からデータを取り出す際に使用したものです。

スクリプト名:リーダー罫文字のあとの文字を取得する
set a to "ひよこさん募集………………………………………………160名"
set b to retAfterRuledLineCharacter(a, "…") of me
b
–> "160名"

set a to "ひよこさんの募集は終了しました"
set b to retAfterRuledLineCharacter(a, "…") of me
b
–> "ひよこさんの募集は終了しました"

–リーダー罫文字のあとの文字を取得する
on retAfterRuledLineCharacter(a, aRulerLineChar)
  if a does not contain aRulerLineChar then
    return a
  end if
  
  
set cList to characters of a
  
set aLen to length of a
  
  
set rList to reverse of cList
  
set rText to rList as string
  
set rOffset to offset of aRulerLineChar in rText
  
  
set resText to text (aLen - rOffset + 2) thru -1 of a
  
  
return resText
end retAfterRuledLineCharacter

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/25 指定フォルダ以下のファイル作成日付をファイル修正日にコピーする

指定フォルダ以下のすべてのファイルの作成日付の情報を取得し、最終修正日の情報にコピーするAppleScriptです。

10数年前に撮影したQuickTake 100のデジタル写真データをPICTからJPEGにコンバートしたのはよかったのですが、iPhotoにインポートしたときに作成日が反映されなかったので、ためしに作ってみました。

なお、実行のためには、Developper Toolsがインストールしてある必要があります。

これでダメなら、本当にEXIFのデータをいじくる必要が(汗)

スクリプト名:指定フォルダ以下のファイル作成日付をファイル修正日にコピーする
set aFol to choose folder
set fList to {}
set f_r to a reference to fList

–外付けHDDをSpotlightの処理対象外に指定していたので、mdfindコマンドを使わなかった
tell application “Finder”
  set fList to entire contents of aFol as alias list
end tell

–メインループ
repeat with i in f_r
  set j to contents of i
  
try
    set aInfo to info for j
    
set aF to folder of aInfo
  on error
    set aF to false
  end try
  
  
if aF = false then
    changeModDateToCreationDate(j) of me
  end if
end repeat

–作成日付の情報を修正情報にコピーする
on changeModDateToCreationDate(aFile)
  tell application “Finder”
    set aInfo to info for aFile
    
set creDate to creation date of aInfo
  end tell
  
set aDateStr to makeMMDDYYYYhhmmssStr(creDate) of me
  
  
set aP to POSIX path of aFile
  
  
try
    do shell script “/usr/bin/SetFile -m “ & quoted form of aDateStr & ” “ & quoted form of aP –修正日
  end try
end changeModDateToCreationDate

–DateオブジェクトからMM/DD/YYYY hh:mm:ssの形式の文字列を返す
on makeMMDDYYYYhhmmssStr(aDate)
  –Dateオブジェクトから各要素を取り出す
  
set yStr to (year of aDate) as string
  
set mStr to (month of aDate as number) as string
  
set dStr to (day of aDate) as string
  
set hhStr to (hours of aDate) as string
  
set mmStr to (minutes of aDate) as string
  
set ssStr to (seconds of aDate) as string
  
  
–桁数を合わせる
  
set y2Str to retZeroPaddingText(yStr, 4) of me
  
set m2Str to retZeroPaddingText(mStr, 2) of me
  
set d2Str to retZeroPaddingText(dStr, 2) of me
  
set hh2Str to retZeroPaddingText(hhStr, 2) of me
  
set mm2Str to retZeroPaddingText(mmStr, 2) of me
  
set ss2Str to retZeroPaddingText(ssStr, 2) of me
  
  
return (m2Str & “/” & d2Str & “/” & y2Str & ” “ & hh2Str & “:” & mm2Str & “:” & ss2Str)
end makeMMDDYYYYhhmmssStr

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to (“0000000000″ & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/25 指定フォルダ以下のPICTファイルをGraphicConverterでJPEGに変換

指定フォルダ以下のすべてのPICTファイルをGraphicConverter(v6.7.3)でJPEGファイルに変換するAppleScriptです。

今をさかのぼること10数年前に発売された、初の商用デジタルカメラ「QuickTake 100」で撮りためた写真を128MBのMO十数枚に保存してありました。

desk.jpg
▲1995/2/7の写真。SPARCstation IPXが写っている

iicx.jpg
▲Macintosh IIcxが写っている。古い……

Preview.appの64ビット起動モード([6][4]を押しながら起動……ではなく、Mac OS X 10.6の32ビット起動&通常アプリ起動)ではQuickTakeのネイティブ記録フォーマットであるPICT(QuickTake PICT)をオープンできなくなっていました。

pr1.jpg

そこで、MOドライブが動くうちに読み取って、JPEGにフォーマット変換しておこうと思い立ち、Graphic ConverterでPICTをオープンできることを確認しました。

gc1.jpg

Graphic Converterは昔からAppleScriptに対応していたのですが、あまりASからコントロールする機会はありませんでした。ひととおり最低限の処理を記述して、1フォルダ分のデータで処理テストを実施。Classic Mac OSのデータをMac OS Xにコピーしてそのまま処理したので、一部で不可解な挙動(file typeを取得する際にエラーが出るとか)がありましたが、とくに問題なくデータ変換できました。

ファイルの作成日が引き継がれないのでは? と心配していましたが、修正日が変更されるだけでとくに変わることはなかったので、あらかじめ作っておいた作成日変更のScriptは使わずじまいに。

Graphic ConverterのScriptingを行って不思議だったのは、画像に対してDocumentオブジェクトでアクセスできずに、Windowオブジェクトを通じてアクセスする必要があること。複数枚の画像をオープンして相互にデータのやりとりを行うような場合には、ちょっと辛い(どうやってWindow同士の区別を行うのか???)感じがします。

あとは、Grachic Converterのプロセスを非表示にして処理を行ったものの、ファイルオープンのアニメーションだけは表示されてしまい、そのあたりは少々不満を覚えたぐらいでしょうか。

スクリプト名:指定フォルダ以下のPICTファイルをJPEGに変換
set aFol to choose folder
set fList to {}
set f_r to a reference to fList

–外付けHDDをSpotlightの処理対象外に指定していたので、mdfindコマンドを使わなかった
tell application “Finder”
  set fList to entire contents of aFol as alias list
end tell

–Graphic Converterを非表示状態に
tell application “System Events”
  tell process “GraphicConverter”
    set visible to false
  end tell
end tell

–メインループ
repeat with i in f_r
  set j to contents of i
  
try
    set aInfo to info for j
    
set aF to folder of aInfo
    
  on error
    set aF to false
  end try
  
  
if aF = false then
    try
      –古いMac OSのファイルにアクセスしたときに、問題が発生することがあったために対処した
      
with timeout of 10 seconds
        tell application “Finder”
          set aType to file type of j
        end tell
      end timeout
      
      
if aType = “PICT” then
        convToJPEG(j) of me
      end if
    end try
    
  end if
end repeat

–指定のファイルをGCでオープンしてJPEGでSave
on convToJPEG(aFile)
  tell application “GraphicConverter”
    –オープン中のドキュメントをすべてクローズ
    
try
      close every window saving no –GCにはDocumentというオブジェクトは定義されていない。すべてwindowで操作
    end try
    
    
silentopen aFile –openコマンドだとエラーやダイアログ表示を行うが、silentopenコマンドだとメッセージが出ないらしい。ただし、非表示オープンモードではない
    
    
set saveRes to (save window 1 in aFile as JPEG without makeCopy and wwwready)
    
–> 保存成功の場合には0が返る
    
    
–オープン中のドキュメントをすべてクローズ
    
try
      close every window saving no
    end try
  end tell
  
  
–保存したファイルにJPEGの拡張子を付ける
  
if saveRes = 0 then
    tell application “Finder”
      set aName to name of aFile
      
set aName to aName & “.jpg”
      
set name of aFile to aName
    end tell
  end if
  
end convToJPEG

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/23 指定矩形座標内に含まれる座標をピックアップ

指定の矩形座標内に含まれる座標をリスト内からピックアップするAppleScriptです。

{y1, x1, y2, x2} 形式で指定した座標内に含まれる座標(InDesignから取得したgeometric bounds)をピックアップします。

スクリプトラベルのついていないText frameからデータを取り出しを行う必要があったときに、他のスクリプトラベルが付いているオブジェクトからの相対矩形座標内に存在するObjectを求めるようにしてみました。その時に試作したものです。

スクリプト名:指定矩形座標内に含まれる座標をピックアップ
set aList to {{243.0, 17.0, 245.0, 77.0}, {169.000015228534, 12.0, 187.500015228534, 166.999999999992}, {189.000007614311, 13.0, 242.000007614312, 17.0}, {188.999990448174, 17.0, 241.999990448174, 76.999999025133}, {188.999990448174, 87.5, 241.999990448174, 123.5}}

set rangeList to {236.999990448174, 12.0, 246.999990448174, 81.999999025133} –{y1,x1,y2,x2}
set resList to withinRange_Y1X1Y2X2(rangeList, aList) of me

–指定矩形内に含まれるデータをリストで返す
on withinRange_Y1X1Y2X2(rangeList, targetList)
  set includedList to {}
  
  
set y1 to item 1 of rangeList
  
set x1 to item 2 of rangeList
  
set y2 to item 3 of rangeList
  
set x2 to item 4 of rangeList
  
  
repeat with i in targetList
    set targY1 to item 1 of i
    
set targX1 to item 2 of i
    
set targY2 to item 3 of i
    
set targX2 to item 4 of i
    
    
if (x1 < targX1) and (x2 > targX2) and (y1 < targY1) and (y2 > targY2) then
      set the end of includedList to (contents of i)
    end if
  end repeat
  
  
return includedList
end withinRange_Y1X1Y2X2

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/22 文字列から数字の部分を取り出してリスト化

文字列から、数字の部分を取り出してリスト化するAppleScriptです。

スクリプト名:文字列から数字の部分を取り出してリスト化
set a to "100名(人間12名、ひよこ88名)"

set aList to characters of a

set aResList to {}

set inF to false –アイテムへの取り込みフラグ:初期値=false(取り込まない)
set oneItem to ""

repeat with i in aList
  set j to contents of i
  
set aF to detectOutNumChar(j) of me –aF:現在のキャラクタがNumericかどうかの判定フラグ
  
  
if aF = true and inF = false then
    set inF to true
    
set oneItem to oneItem & j
    
  else if aF = true and inF = true then
    set oneItem to oneItem & j
    
  else if aF = false and inF = true then
    set the end of aResList to oneItem
    
set oneItem to ""
    
set inF to false
    
  else if aF = false and inF = false then
    –なにもしない
    
  end if
end repeat

if oneItem is not equal to "" then
  set the end of aResList to oneItem
end if

aResList
–> {"100", "12", "88"}

–数字範囲外の文字があるかどうかをテストする
–数字の文字以外のものが入っていたらfalse
on detectOutNumChar(testText)
  –ANK文字列(大文字小文字は問わない)
  
set ankChar to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "."}
  
  
set _testChar to testText as Unicode text
  
  
ignoring case
    repeat with i in _testChar
      set j to contents of i
      
if j is not in ankChar then
        return false
      end if
    end repeat
  end ignoring
  
  
return true
end detectOutNumChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/21 Numbersで選択範囲を横に区切ったリストを返す

Numbers 2で、選択範囲を横に区切ったリストを返すAppleScriptです。

「機能がないならないなりに、Appleに頼らずに機能を追加するシリーズ」の第2弾です。

Numbersの選択範囲から、データが行ごとに入れ子になったリストを返します。Excelと同じ動作を行う、といったほうが早いかもしれません。

こういう状態で、

number2.jpg

実行すると、

 {{”Apple”, “Lemon”, “Strawberry”}, {10.0, 20.0, 30.0}}

と結果が返ってきます。

スクリプト名:Numbersで選択範囲を横に区切ったリストを返す
–Numbersで選択範囲を縦に区切ったリストを返す
tell application "Numbers"
  tell document 1
    tell sheet 1
      tell table 1
        set selList to value of every cell of selection range –選択範囲のデータを取得
        
        
set selName to name of selection range –選択範囲のrange情報を取得
        
set {s1, s2} to parseByDelim(selName, ":") of me
        
        
–始点の情報を取得する
        
set s1Row to (address of row of range s1) as integer
        
set s1Column to (address of column of range s1) as integer
        
        
–終点の情報を取得する
        
set s2Row to (address of row of range s2) as integer
        
set s2Column to (address of column of range s2) as integer
        
        
–選択範囲の情報を取得する
        
set selHeight to s2Row - s1Row + 1 –高さ(Height of selection range)
        
set selWidth to s2Column - s1Column + 1 –幅(Width of selection range)
        
      end tell
    end tell
  end tell
end tell

set aLen to length of selList
set aaLen to selHeight

set bList to {}
repeat with i from 1 to aaLen
  set aHoriList to {}
  
  
repeat with ii from 1 to selWidth
    set j1 to ii + (i - 1) * selWidth
    
set the end of aHoriList to contents of item j1 of selList
  end repeat
  
  
set the end of bList to aHoriList
end repeat

bList
–> {{"Apple", "Lemon", "Strawberry"}, {10.0, 20.0, 30.0}}

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/21 Numbersで選択範囲を縦に区切ったリストを返す

Numbers 2で、選択範囲のデータを縦に区切ったリストを返すAppleScriptです。

そもそも、Excelでは行ごとに横に区切ったリストが返ってくるのですが、Numbersでは複数行にまたがって選択した状態でデータを取得しても、行ごとに分けられた入れ子のリストでデータが返ってくるわけではありません。

そこで、機能がないならないなりに、選択範囲からさまざまな形でデータを取り出すAppleScriptを書いてみました。

このScriptは、

number1.jpg

という状態で実行すると、

 {{”Apple”, 10.0}, {”Lemon”, 20.0}, {”Strawberry”, 30.0}}

と、結果が返ってきます。

スクリプト名:Numbersで選択範囲を縦に区切ったリストを返す
–Numbersで選択範囲を縦に区切ったリストを返す

tell application "Numbers"
  tell document 1
    tell sheet 1
      tell table 1
        set selList to value of every cell of selection range –選択範囲のデータを取得
        
        
set selName to name of selection range –選択範囲のrange情報を取得
        
set {s1, s2} to parseByDelim(selName, ":") of me
        
        
–始点の情報を取得する
        
set s1Row to (address of row of range s1) as integer
        
set s1Column to (address of column of range s1) as integer
        
        
–終点の情報を取得する
        
set s2Row to (address of row of range s2) as integer
        
set s2Column to (address of column of range s2) as integer
        
        
–選択範囲の情報を取得する
        
set selHeight to s2Row - s1Row + 1 –高さ(Height of selection range)
        
set selWidth to s2Column - s1Column + 1 –幅(Width of selection range)
        
      end tell
    end tell
  end tell
end tell

set aLen to length of selList
set aaLen to selWidth

set bList to {}
repeat with i from 1 to aaLen
  set aVerList to {}
  
  
repeat with ii from 1 to selHeight
    set j1 to i + (ii - 1) * aaLen
    
set the end of aVerList to contents of item j1 of selList
  end repeat
  
  
set the end of bList to aVerList
end repeat

bList
–> {{"Apple", 10.0}, {"Lemon", 20.0}, {"Strawberry", 30.0}}

on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/21 ファイル作成日付を変更する

ファイル作成日付および最終変更日を変更するAppleScriptです。

AppleScriptからFinderをコントロールしても作成日/変更日は変更できないため、shellコマンドを呼び出してくることになります。

Developper Toolsをインストールすると一緒に入ってくるSetFileコマンド(/usr/bin/SetFile)を呼び出します。Developper Toolsをインストールしていない環境ではSetFileがそもそも存在していないので、本Scriptを実行しても日付の変更は行われません。

昔に撮りためたQuickTake 100の写真データをコンバートしようとして、QuickTake PICTをGraphic Converterでオープンできることを確認したのですが、作成日付に当時のもの(15年ぐらい昔)を残しておきたいと思い立ち、作成日の変更方法を調べてみた次第です。

スクリプト名:ファイル作成日付を変更する
set a to choose file with prompt "作成日付の情報をピックアップするファイルを選択してください"
tell application "Finder"
  set aInfo to info for a
  
set creDate to creation date of aInfo
end tell
set aDateStr to makeMMDDYYYYhhmmssStr(creDate) of me

set b to choose file with prompt "日付情報を変更するファイルを選択してください"
set bP to POSIX path of b

try
  do shell script "/usr/bin/SetFile -d " & quoted form of aDateStr & " " & quoted form of bP –作成日
  
do shell script "/usr/bin/SetFile -m " & quoted form of aDateStr & " " & quoted form of bP –修正日
end try

–DateオブジェクトからMM/DD/YYYY hh:mm:ssの形式の文字列を返す
on makeMMDDYYYYhhmmssStr(aDate)
  –Dateオブジェクトから各要素を取り出す
  
set yStr to (year of aDate) as string
  
set mStr to (month of aDate as number) as string
  
set dStr to (day of aDate) as string
  
set hhStr to (hours of aDate) as string
  
set mmStr to (minutes of aDate) as string
  
set ssStr to (seconds of aDate) as string
  
  
–桁数を合わせる
  
set y2Str to retZeroPaddingText(yStr, 4) of me
  
set m2Str to retZeroPaddingText(mStr, 2) of me
  
set d2Str to retZeroPaddingText(dStr, 2) of me
  
set hh2Str to retZeroPaddingText(hhStr, 2) of me
  
set mm2Str to retZeroPaddingText(mmStr, 2) of me
  
set ss2Str to retZeroPaddingText(ssStr, 2) of me
  
  
return (m2Str & "/" & d2Str & "/" & y2Str & " " & hh2Str & ":" & mm2Str & ":" & ss2Str)
end makeMMDDYYYYhhmmssStr

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to ("0000000000" & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/18 Snow Leoaprdで追加になったsayコマンドのパラメータテスト3

Snow Leopardで追加になったsayコマンドのパラメータテストです。

従来、テキストの読み上げ内容をファイルに書き出す場合には、それなりに……読み上げに要する時間と同等の時間が必要でしたが、Snow Leopard上では読み上げ時間よりもはるかに短い時間でファイル出力が可能であることを確認しました(MacBook Pro Core i7 2.66GHz+Mac OS X 10.6.4)。

「without waiting until completion」オプションを付けても付けなくても、それほど有為な速度差は見られません。実際にサンプルプログラムが書き出した音声ファイルは、再生するのに24秒程度かかるため、それと比べればはるかに短い時間で書き出し(音声レンダリング)ができています。

スクリプト名:Snow Leoaprdで追加になったsayコマンドのパラメータテスト3
set iiwakeText to “The opposite of amplification, attenuation happens whenever a signal is obstructed. All antennas ― including television, radio, GPS, and cellular antennas ― can experience attenuation. And with most antennas, the density and composition of the human hand can cause attenuation to a greater degree than some other materials. On a mobile phone, signal loss typically occurs when your hand attenuates the most sensitive part of the antenna. In the photos and videos below, we demonstrate how different grips cause attenuation on many popular smartphones ― including iPhone 4 and iPhone 3GS.”

set vFile to choose file name –ファイル名入力と保存先フォルダを選択
say iiwakeText saving to vFile using “Alex” without waiting until completion

–ファイル名の後始末
set vFileAlias to vFile as alias
tell application “Finder”
  set vN to name of vFileAlias
  
if vN does not end with “.aif” then
    set name of vFileAlias to vN & “.aif”
  end if
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/18 Snow Leopardで追加になったsayコマンドのパラメータをテスト

Snow Leopardで追加になったsayコマンドのパラメータをテストするAppleScriptです。

US AppleのAppleScript Users MLで話題になっていました。まさかそんなところに機能追加があったとは…………。

音の高さ、長さ、速さなどを指定できるようになったようです。つまり、歌わせることができるようになったような、まだそこまで行っていないような。

say1.jpg

スクリプト名:Snow Leopardで追加になったsayコマンドのパラメータをテスト
–高さを高くする
repeat with i from 30 to 80 by 10
  say “piomaru” pitch i speaking rate 200 using “Alex”
end repeat

–スピードを速くする
repeat with i from 100 to 1000 by 100
  say “piomaru” pitch 50 speaking rate i using “Alex”
end repeat

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

音階にも対応したようなので、これについても試してみました。音階データはここからひろってきました

ボイスキャラクターによっては、音階を指定しても結果に反映されません。Good NewsとかHistericalなどがそれに該当します。普通にしゃべるボイスキャラクターなら大丈夫です。

スクリプト名:Snow Leopardで追加になったsayコマンドのパラメータをテスト2
property vList : {“Agnes”, “Albert”, “Alex”, “Bad News”, “Bahh”, “Bells”, “Boing”, “Bruce”, “Bubbles”, “Cellos”, “Deranged”, “Fred”, “Good News”, “Hysterical”, “Junior”, “Kathy”, “Pipe Organ”, “Princess”, “Ralph”, “Trinoids”, “Vicki”, “Victoria”, “Whisper”, “Zarvox”}

set aList to {60, 62, 64, 65, 67, 69, 71, 72}
set bList to reverse of aList
set cList to aList & bList

repeat with ii in vList
  repeat with i in cList
    say “iPad” pitch i speaking rate 300 using ii
  end repeat
end repeat

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/17 Photoshopで複数画像の「差の絶対値」を計算するテスト v3

Photoshopで、2つのフォルダに入っている同名のファイル同士を「差の絶対値」(difference)で比較して、演算結果をPhotoshop形式で指定のフォルダに保存するAppleScriptです。

画像出力するプログラムの実行テストを行っていて、各種パラメータを変更した状態で演算。それぞれ、演算結果にシリアル番号を付けて保存……そうした演算テストを異なるOSのマシン上で行って、その結果が合っているかどうかを確認したい場合に双方の内容を「差の絶対値」(difference)で計算して画像保存します。

前に、Windows版のアプリケーションをMac OS Xに移植するという仕事をしたときに、変更可能なパラメータをすべての組み合わせで数百通り計算し、その結果をファイルに出力するようAppleScriptで外部からコントロールしていました。そこまでは、「プログラムのテストをAppleScript(GUI Scripting)で自動化できてよかった」という話だったのですが……困ったのが、それらの結果をどうやって付け合わせるか、ということでした。

そこで、Photoshopを使って「差の絶対値」でWindows版とMac版の演算結果を比較。同じなら真っ黒になりますが、差があれば明るいピクセルが出てきます。当時は、Photoshopで画像のヒストグラムを簡単に取得できることには気付いていなかったため、Finder上に画像をならべてプレビューアイコンの画像から「このあたりで違いが出ている」などと目視で判断していました。

いまでは、Photoshopでヒストグラムを取得することなど、朝飯前であるため……この演算結果からヒストグラムを取得し、「どの画像がどのぐらい違っていた」というデータを自動で取得できるようになったというわけです。なお、本サンプルではヒストグラムの取得と集計は盛り込んでおりません。

本プログラムは、PhotoshopをAppleScriptから操作する基本的な動作を数多く含んでいます。とくに、レイヤー合成モードを「差の絶対値」に設定する方法は海外のWebを探しまわっても見つからなかったので、非常に有用なものと思われます。

スクリプト名:Photoshopで複数画像の「差の絶対値」を計算するテスト v3

set doc1Folder to choose folder with prompt “画像1フォルダを選択してください”
set doc2Folder to choose folder with prompt “画像2フォルダを選択してください”
set outFol to choose folder with prompt “合成画像の出力用フォルダを指定してください”

set doc1FolderStr to doc1Folder as string
set doc1FolderStr to doc1FolderStr as Unicode text

set doc2FolderStr to doc2Folder as string
set doc2FolderStr to doc2FolderStr as Unicode text

set outFolStr to outFol as string
set outFolStr to outFolStr as Unicode text

tell application “Finder”
  tell folder doc1Folder
    set doc1Files to name of every file whose name ends with “.jpg”
  end tell
  
  
tell folder doc2Folder
    set doc2Files to name of every file whose name ends with “.jpg”
  end tell
  
  
if (length of doc1Files) is not equal to (length of doc2Files) then
    display dialog “エラー:画像1側と画像2側のファイル数が異なります”
    
return
  end if
end tell

–Photoshop CS3のRulerをPixelに設定
changeRulerToPXL() of me

set fLen to length of doc1Files

repeat with i from 1 to fLen
  set doc1Name to (contents of item i of doc1Files)
  
set doc2Name to (contents of item i of doc2Files)
  
  
–ファイル名が違っていた場合にはエラー
  
if doc1Name is not equal to doc2Name then
    display dialog “2つの画像フォルダに入っているファイル名が違っています” buttons {“OK”} default button 1 with icon 1
    
return
  end if
  
  
set doc1FilePath to doc1FolderStr & doc1Name
  
set doc2FilePath to doc2FolderStr & doc2Name
  
  
set savePath to outFolStr & (contents of item i of doc1Files)
  
  
tell application “Adobe Photoshop CS3″
    activate
    
    
–画像1をオープン
    
open (doc1FilePath as alias) showing dialogs never
    
set d1Doc to (a reference to current document)
    
    
tell d1Doc
      –サイズなどを取得
      
set hSize to height
      
set wSize to width
      
set aResol to resolution
      
      
–内容をすべてコピーしてクローズ    
      
select all
      
copy
      
close without saving
    end tell
    
    
–画像1と同じサイズの画像を新規作成する
    
set newDoc to make new document with properties {name:“composed_image”, width:wSize, height:hSize, resolution:aResol, mode:RGB, bits per channel:eight, initial fill:transparent, color profile kind:none, pixel aspect ratio:1.0}
    
tell newDoc
      set a1Layer to (make new art layer with properties {name:“doc1″})
      
set current layer to a1Layer
      
tell a1Layer
        paste –画像1をペースト
      end tell
    end tell
    
    
–画像2をオープン
    
open (doc2FilePath as alias) showing dialogs never
    
set d2Doc to (a reference to current document)
    
    
–内容をすべてコピーしてクローズ    
    
tell d2Doc
      select all
      
copy
      
close without saving
    end tell
    
    
tell newDoc
      set a2Layer to (make new art layer with properties {name:“doc2″})
      
set current layer to a2Layer
      
tell a2Layer
        paste
      end tell
      
      
set current layer to layer 1
      
      
–レイヤー1の合成フォーマットを「差の絶対値」に
      
tell layer 1
        set blend mode to difference
      end tell
      
      
      
set savedDoc to (save in file savePath as Photoshop format) –一度保存すると、それまでのドキュメントへの参照が無効になるので、再度参照を取得
    end tell
    
    
tell savedDoc to close without saving
    
  end tell
  
end repeat

–Photoshopの定規単位をpixelに変更
on changeRulerToPXL()
  tell application “Adobe Photoshop CS3″ to setRulerPref(pixel units) of me
end changeRulerToPXL

–Photoshopの定規単位を設定
–パラメータ1:cm units/inch units/mm units/percent units/pica units/pixel units/point units
on setRulerPref(myRuler)
  tell application “Adobe Photoshop CS3″
    set ruler units of settings to myRuler
  end tell
end setRulerPref

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/14 アドレスブックプラグイン例(email)

アドレスブックのプラグインAppleScriptのサンプルです。

Mac OS X標準搭載のアドレスブックは、メールや電話番号などの欄の左側にポップアップメニュー表示ボタンが付いており、クリックするとポップアップメニューが表示されるようになっています。電話番号を「大きな文字で表示」したり、住所から「この住所の地図を表示」させたりする機能が標準搭載されています。

adb1.jpg

このポップアップメニューをAppleScriptで拡張できるようになっています。

決められた形式で記述しておいたAppleScriptを~/ライブラリ/Address Book Plug-Insフォルダに入れておくだけで、アドレスブックの起動時にこのフォルダ中のAppleScriptを読み込んで、Script中で宣言している対応データ欄の左側をクリックした際にポップアップ表示。

adb21.jpg

その中に、AppleScript中で宣言した文字列を表示。ポップアップ中から項目を選択すると、実際にAppleScript内のハンドラが呼び出されます。

adb3.jpg

通常のAppleScript内で処理を行うもよし、GUIベースのアプリケーションをAppleScript Studio/AppleScriptObjCで記述してデータを渡すもよし、いろいろAppleScriptのプログラムとアドレスブックを連携させることが可能です。

実際に、アドレスブックとGUIベースのAppleScript Studioアプリケーションを連携させ、データの登録をアドレスブックから選択して行うようにしてみました(ASとASSアプリの連携を行うための試作品がこれです)。割と、いろいろと有用な応用が行える機構です。

アドレスブックのプラグインScriptは、通常のScript形式で保存しておいて大丈夫です。iChatの拡張Scriptのようにテキスト形式で保存しておく必要はありません。ファイル名にもとくにルールはありません。

スクリプト名:アドレスブックプラグイン例(email)
using terms from application “Address Book”
  –どの種類のデータに対してポップアップ項目を表示するか
  
on action property
    return “email” –1つのプラグイン内で複数の種別のデータに応答することはできない
  end action property
  
  
–データの有無に応じてポップアップを表示するかどうかの制御
  
on should enable action for thePerson with theEntry
    if theEntry is not equal to missing value then
      return true
    else
      return false
    end if
  end should enable action
  
  
–ポップアップメニュー上に表示する項目名
  
on action title for thePerson with theEntry
    return “ぴよまるメールアドレスぷらぐいん”
  end action title
  
  
–ポップアップメニューから項目を選んで実行される
  
on perform action for thePerson with theEntry
    set theAddress to value of theEntry –この場合、theEntryはemailオブジェクトなので、valueを取るとメールアドレスが返ってくる
    
set theLabel to label of theEntry –emailのラベル
    
    
    
display dialog “メールアドレス:” & theAddress & return & “ラベル:” & theLabel buttons {“OK”} default button 1 with icon 1
    
  end perform action
end using terms from

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/13 アドレスブックでmy cardがあるかどうか取得する

アドレスブックに自分の情報(my card)があるかどうかを取得するAppleScriptです。

所有者情報をもとに処理を行うような場合に、アドレスブックからユーザーの情報を取得するような処理を書くことが、よくあります(無断でやったらウィルスまがいの処理ですが……)。

ただ、世の中は広いもので……アドレスブックにまともに情報が入っていないような悲惨なコンフィグレーションの環境が存在しており、そういうマシン上で「アドレスブックにはmy cardが存在しているに違いない」という前提のAppleScriptを走らせるとエラーになってしまいます。

そこで、my cardが存在しているかどうかを最初に確認しておくという処理が必要になってきます。

処理内容は、さほど面白くもなんともないものですが……「my cardが登録されていないような環境が存在する」という事実のほうが実に興味深いところです。

スクリプト名:アドレスブックでmy cardがあるかどうか取得する
set abRes to checkMYCARDonADB() of me

–アドレスブックに自分のカードが登録されていないかどうかをチェック
on checkMYCARDonADB()
  tell application "Address Book"
    try
      set myCard to my card
      
return true
    on error
      return false
    end try
  end tell
end checkMYCARDonADB

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/13 数値の序数の文字列を返す

数値を渡すと、英語の序数(1st, 2ndなど)の文字列を返すAppleScriptです。

あまり面白味も何もないのですが、必要に迫られて作成したものです。1->1st、11->11th、21->21st……と、11,12,13の時だけ例外処理を行っています。

AppleScriptのsayコマンドに「11st」などと間違った序数を渡しても、「11th」と言い換えたりしているので、OS内部には序数の処理機能が入っているはずですが、ASからは利用できません。

単なるif文の塊になっていますが、まあこんな感じではないでしょうか。

スクリプト名:数値の序数の文字列を返す
repeat with i from 1 to 100
  set a to retOrdinalNumStr(i) of me
  
log a
end repeat

–数値を与えると序数の文字列を返す
on retOrdinalNumStr(aNum)
  set aStr to aNum as string
  
  
–下1桁の数字を取得
  
set last1Str to last character of aStr
  
  
–下2桁目の数字を取得
  
if length of aStr > 1 then
    set last2Str to character -2 of aStr
  else
    set last2Str to “”
  end if
  
  
–場合分け
  
set retStr to “”
  
if last1Str = “1″ then
    if last2Str = “1″ then
      set retStr to “th” –11
    else
      set retStr to “st”
    end if
    
  else if last1Str = “2″ then
    if last2Str = “1″ then
      set retStr to “th” –12
    else
      set retStr to “nd”
    end if
    
  else if last1Str = “3″ then
    if last2Str = “1″ then
      set retStr to “th” –13
    else
      set retStr to “rd”
    end if
    
  else
    set retStr to “th”
    
  end if
  
  
return aStr & retStr
  
end retOrdinalNumStr

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/10 iPhotoで選択中のファイルをリネームする

iPhotoで選択中のファイルをリネームするAppleScriptです。

iPhotoで選択中の写真/ムービーのファイル名については、そのままname属性を書き換えれば変わるというわけには行きません。

iPhotoのAppleScript用語辞書を見ると「r/o」(リードオンリー、書き込み不可)にはなっていないのですが、実際に操作してみるとファイル名の変更は通りません。

そこで、選択中の写真/ムービーのオリジナルのファイルのパスを取得しておき、これをデスクトップフォルダ上にコピーして、リネーム(作成日時の文字列にリネーム)。オリジナルの写真/ムービーを削除した後に、リネームしたファイルをインポートすればよいのではないかと考えました。

インポートについては、いままでそんな操作をAppleScriptから行う必要に迫られたことがなかったので、海外のMLの過去ログやWebサイトを巡回して調査を行う必要がありました。調査に時間はかかりましたが、インポートはできました。

予想外にてこずらされたのが、iPhotoライブラリ上からの画像/ムービーの削除で……スマートアルバム上から削除しようとすると、これが行えないことが判明。このあたりは、「GUI側から行えない操作はAppleScript側からも行えない」という大原則(これを理解できていない人が多い)が適用されており、実際にGUI側から操作して動作内容を把握。

削除を行う際には削除可能なアルバム表示に切り換えてから行うようにしてみました。

ちょっとは楽しめましたが、処理が煩雑な割には最終的な処理結果は大したものではなく、そもそもこんなに手間がかかる処理を実際に書くこと自体に問題があるものと思われます。わざわざ難しいテーマを自分で設定して挫折するのではなく、難易度を下げて「もっと簡単なプログラム」で済むように前提条件を変更するほうが生産的です。

本テーマも、Twitter上でみかけて取り組んでみたのですが、iPhotoからオリジナルのファイルを取り出してリネームし、QuickTime Player X側でYoutubeにアップロードした方が簡単だったのではないかと思われました。

スクリプト名:iPhotoで選択中のファイルをリネームする
tell application "iPhoto"
  set a to selection –iPhoto上で選択中の写真/ムービーのうち最初のものを処理対象に
  
if a = {} then return –何も選択されていなかったら処理終了
  
set aa to first item of a
  
  
set aInfo to properties of aa
  
set makeDate to date of aInfo –作成日
  
set iPPath to original path of aa –オリジナルファイルのパス
end tell

–iPhotoで選択しておいた写真/ムービーをデスクトップ上にコピーして日付でリネーム
–確実に動作することを重視したので、速度の最適化は行っていない段階
set aPhoto to (POSIX file iPPath) as alias –ASで処理しやすいよう、POSIX pathからaliasに変換(iPhotoがPOSIX pathを返して来るのがおかしい)
set dtPath to path to desktop from user domain

tell application "Finder"
  with timeout of 3600 seconds –バカでかいファイルを遅いマシンでコピーしている場合への対策
    set dPath to (duplicate aPhoto to folder dtPath with replacing) –コピー
  end timeout
  
  
set dPath to dPath as alias –処理しやすいようaliasにcast
  
set aExt to (name extension of dPath) –拡張子をオリジナルのファイル名から取り出し
  
  
set name of dPath to makeYYYYMMDDhhmmssStr(makeDate) of me & "." & aExt –リネーム
end tell

tell application "iPhoto"
  set origAlbum to current album –現在表示中のアルバムを取得
  
set aType to type of origAlbum –表示中のアルバムのタイプを取得
  
  
–スマートアルバム上では写真/ムービーの削除が行えないので、確実に削除できるアルバムに変更しておく
  
–このへん、まだ試行錯誤の最中
  
if aType = smart album then
    select album "写真" –写真/ムービーが削除可能なアルバムを選択しておく
    
select aa –再度、写真/ムービーを選択状態に
  end if
  
  
remove aa –最初に選択していた写真/ムービーを削除
  
  
with timeout of 3600 seconds –遅いマシンへの対策
    import from {dPath} to album "最後の読み込み"
  end timeout
  
  
set current album to origAlbum
end tell

–DateオブジェクトからYYYY-MM-DD-hh-mm-ssの形式の文字列を返す
on makeYYYYMMDDhhmmssStr(aDate)
  
  
–Dateオブジェクトから各要素を取り出す
  
set yStr to (year of aDate) as string
  
set mStr to (month of aDate as number) as string
  
set dStr to (day of aDate) as string
  
set hhStr to ((time of (aDate)) div 3600) as string
  
set mmStr to ((time of (aDate)) mod 3600 div 60) as string
  
set ssStr to ((time of (aDate)) mod 3600 mod 60) as string
  
  
–桁数を合わせる
  
set y2Str to retZeroPaddingText(yStr, 4) of me
  
set m2Str to retZeroPaddingText(mStr, 2) of me
  
set d2Str to retZeroPaddingText(dStr, 2) of me
  
set hh2Str to retZeroPaddingText(hhStr, 2) of me
  
set mm2Str to retZeroPaddingText(mmStr, 2) of me
  
set ss2Str to retZeroPaddingText(ssStr, 2) of me
  
  
return (y2Str & "-" & m2Str & "-" & d2Str & "-" & hh2Str & "-" & mm2Str & "-" & ss2Str)
  
end makeYYYYMMDDhhmmssStr

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to ("0000000000" & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/10 DateオブジェクトからYYYY-MM-DD-hh-mm-ssの形式の文字列を返す

DateオブジェクトからYYYY-MM-DD-hh-mm-ss形式の文字列を取得するAppleScriptです。

Dateオブジェクトから特定形式の文字列を取り出す処理は、ひじょうによくあるものですが、よくある割に短く書けないので……少々苦労させられてしまうところです。

スクリプト名:DateオブジェクトからYYYY-MM-DD-hh-mm-ssの形式の文字列を返す
set aDate to current date
set aStr to makeYYYYMMDDhhmmssStr(aDate) of me
–> "2010-07-10-09-54-40"

–DateオブジェクトからYYYY-MM-DD-hh-mm-ssの形式の文字列を返す
on makeYYYYMMDDhhmmssStr(aDate)
  –Dateオブジェクトから各要素を取り出す
  
set yStr to (year of aDate) as string
  
set mStr to (month of aDate as number) as string
  
set dStr to (day of aDate) as string
  
set hhStr to ((time of (aDate)) div 3600) as string
  
set mmStr to ((time of (aDate)) mod 3600 div 60) as string
  
set ssStr to ((time of (aDate)) mod 3600 mod 60) as string
  
  
–桁数を合わせる
  
set y2Str to retZeroPaddingText(yStr, 4) of me
  
set m2Str to retZeroPaddingText(mStr, 2) of me
  
set d2Str to retZeroPaddingText(dStr, 2) of me
  
set hh2Str to retZeroPaddingText(hhStr, 2) of me
  
set mm2Str to retZeroPaddingText(mmStr, 2) of me
  
set ss2Str to retZeroPaddingText(ssStr, 2) of me
  
  
return (y2Str & "-" & m2Str & "-" & d2Str & "-" & hh2Str & "-" & mm2Str & "-" & ss2Str)
  
end makeYYYYMMDDhhmmssStr

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to ("0000000000" & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/09 iPhotoに指定画像をインポートする

iPhoto 09で、指定画像をインポートするAppleScriptです。

画像をリストに入れて指定します。それなりの数を指定した場合には、比例して取り込み時間がかかるので、大量の取り込みを行う場合にはタイムアウト時間の指定を(with timeout of XXXX seconds)行う必要があることでしょう。

インポート先を行うアルバム名が「最後の読み込み」という、日本語ローカライズされた名前を指定する必要があり、このあたり……アプリケーションごとにローカライズされた名称を求められたり、英語環境の名称を求められたりと方針がバラバラなので、どーにかしてほしいものです。

スクリプト名:iPhotoに指定画像をインポートする
set aFile to choose file
set aLIst to aFile as list

tell application “iPhoto”
  import from aLIst to album “最後の読み込み” –英語環境だと”New images”
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/08 Mail.appで選択しておいたメッセージに返信してsubjectと本文を加える

Mail.app上で選択しておいたメッセージの返信メッセージをreplyコマンドで作成し、その返信メッセージのサブジェクトと本文を変更するAppleScriptです。

USのAppleScript Users MLに投稿があった質問に答えておいたものです。どうも、Mail.appの動作が遅いらしくて……AppleScriptがMail.app側の動作を待ち切れず、返信メッセージを作成し終わる前に次のステップに進んでしまうため、delayコマンドなしではエラーが出てしまっていました。

GUI上でだいたい現象は観察できていたので、delayコマンド(最小限でいいので待機時間は0.1秒)を入れて動作を確認できました。3箇所に入れているdelayコマンドのうち、たぶん最初のものだけが必要不可欠なもので、あとの2つは「おまじない」に近いものです。ウチのCore i7 2.66GHzのMacBook Proではそのように感じられました。もっと高速で大量にCPU Coreが乗っているMac Proでは状況が違うかもしれません。

AppleScriptの処理系自体は、世間で言われるほど遅くないため……アプリケーションの状態を取得したり命令を発行したりすると、(AppleScript側が)けっこう待たされる感じです。そのため、アプリケーションとの通信頻度を下げることで大幅なスピードアップを図ったり、AppleScriptだけで処理をすることで速度を稼いだりするというテクニックが存在します。

やや、Mail.app側のバグのようにも見えますが、AppleScriptチームがMail.appチームを説得するには相当時間がかかりそうなので、Apple側が社内で対応する前に自衛手段を講じておくというのが、ベストな対策といったところでしょうか。

スクリプト名:Mail.appで選択しておいたメッセージに返信してsubjectと本文を加える
tell application “Mail”
  set msg to selection –Mail.appでメッセージを選択状態にしておく
  
set msg to first item of msg
  
  
set replied_msg to reply msg with opening window –選択しておいたメールの返信メッセージを作成
  
delay 0.1
  
  
–返信メッセージに対して操作を加える。
  
tell replied_msg
    set subject to “replied message”
    
delay 0.1
    
    
set content to “this is a replied message”
    
delay 0.1
    
  end tell
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/04 iEPGのファイルから各種情報を取り出してみるテスト v4

iEPGのファイルから、各種情報を取り出してm2TVで録画予約するための文字列を作成するAppleScriptです。

iEPGファイルをparseして、属性ラベルとデータのペアリストにして、さらにペアリストからレコードを作成。レコードにするとデータの扱いが楽になるので、取り出してm2TVが理解できそうな文字列に変換してみました。

テレビ局の情報がiEPGに記載されているものと、m2TVが理解できるものとで差がありそうで(「TBS」と「TBSテレビ」の違いなど)、実際に試してみる必要がありますが……iEPGに書かれているテレビ局名で録画予約が行えない場合には、テレビ局名の置換テーブルでも用意しておく必要がありそうです(その場合は、とりあえず東京エリアを対象にして試作)。

ただ、実際にm2TVにイベントを送ってみたら……以前は動いていたAppleScript(単に固定パラメータで録画予約するだけ)が動かなくなっていました(ーー;;;; 10.6.3のときには動いていたのですが、10.6.4にアップデートした環境で動いていません。

ここまで作ってみたので、出先でiEPGファイルをダウンロードして、メールに録画情報の文面を入れて送信し……自宅でスタンバイしているMacで録画予約を実行し、本当に録画予約できたかどうか設定ファイルを調べて、メールで返信を行う……といったフローを確立できるかと思っていましたが、この調子ではm2TVではとても無理そうで、大変残念です。

スクリプト名:iEPGのファイルから各種情報を取り出してみるテスト v4
set anAlias to choose file
set aData to read anAlias
set aData to aData as Unicode text

–iEPGのデータから取り出すラベル値のリスト
set pList to {“Content-type:”, “version:”, “station:”, “year:”, “month:”, “date:”, “start:”, “end:”, “program-title:”, “subgenre:”, “genre:”}
set dList to {}

repeat with i in pList
  set j to contents of i
  
  
set aRes to trimStrFromTo2(aData, j, (ASCII character 13) & (ASCII character 10)) of me
  
if aRes is not equal to “” then
    set aRes to repChar(aRes, return, “”) of me
  end if
  
  
set the end of dList to {j, aRes}
end repeat

set bRec to makeRecordFromList(dList) of me

–m2TVで録画予約できるように、iEPGから取り出した情報を適宜組み立てる
set aTitle to | program-title | of bRec

set sTime to | start | of bRec
set sTime to repChar(sTime, “:”, “”) of me

set eTime to | end | of bRec
set eTime to repChar(eTime, “:”, “”) of me

set aDate to | month | of bRec & | date | of bRec

set aStation to | station | of bRec

set m2tvRecStr to “tv “ & aStation & ” “ & sTime & ” “ & eTime & ” “ & aDate & return & aTitle & return

–>
(*
“tv テレビ朝日 2100 2251 0703
土曜ワイド劇場「東京駅お忘れ物預り所4」[デ][字]

*)

on trimStrFromTo2(aStr, fromStr, toStr)
  if fromStr is not equal to “” then
    set sPos to (offset of fromStr in aStr)
  else
    set sPos to 0
  end if
  
  
if sPos = 0 then
    return “”
  else
    set sPos to sPos + 1
  end if
  
  
if toStr is not equal to “” then
    set aLen to length of fromStr
    
set b to text (sPos + aLen) thru -1 of aStr
    
set ePos to (offset of toStr in b)
  else
    set ePos to length of aStr
  end if
  
set aRes to text 1 thru ePos of b
  
return aRes
end trimStrFromTo2

on makeRecordFromList(aList)
  set quotChar to (ASCII character 34)
  
  
set s_header to “return {”
  
set recList to {}
  
set s to “”
  
  
set itemCount to count aList
  
  
repeat with i from 1 to itemCount
    set j to ((contents of item 1 of item i of aList) as Unicode text)
    
if j contains “:” then
      set j to repChar(j, “:”, “”) of me
    end if
    
    
set aLabel to “| “ & j & ” |”
    
set aValue to ((contents of item 2 of item i of aList) as Unicode text)
    
set s to s & aLabel & “:” & quotChar & aValue & quotChar
    
if i is not itemCount then
      set s to s & “,”
    end if
  end repeat
  
  
set s to s_header & s & “}”
  
set aRes to run script (s as Unicode text)
  
  
return aRes
  
end makeRecordFromList

–文字置換
on repChar(origText, targChar, repChar)
  set origText to origText as string
  
set targChar to targChar as string
  
set repChar to repChar as string
  
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/04 iEPGのファイルから各種情報を取り出してみるテスト v3

iEPGのファイルから各種情報を取り出すAppleScriptの試作品です。

iEPGのファイルから各ラベル要素を取り出し、属性ラベルとデータのペアリストにして、さらにそれを「リストをレコード化」するサブルーチンを使うことでレコード化します。

スクリプト名:iEPGのファイルから各種情報を取り出してみるテスト v3
set anAlias to choose file
set aData to read anAlias
set aData to aData as Unicode text

–iEPGのデータから取り出すラベル値のリスト
set pList to {"Content-type:", "version:", "station:", "year:", "month:", "date:", "start:", "end:", "program-title:", "subgenre:", "genre:"}
set dList to {}

repeat with i in pList
  set j to contents of i
  
  
set aRes to trimStrFromTo2(aData, j, (ASCII character 13) & (ASCII character 10)) of me
  
if aRes is not equal to "" then
    set aRes to repChar(aRes, return, "") of me
  end if
  
  
set the end of dList to {j, aRes}
end repeat

set bRec to makeRecordFromList(dList) of me
bRec
–> {| content-type |:"application/x-tv-program-info; charset=shift_jis", | version |:"1", | station |:"TBSテレビ", | year |:"2010", | month |:"07", | date |:"03", | start |:"21:00", | end |:"21:54", | program-title |:"世界・ふしぎ発見!", | subgenre |:"", | genre |:""}

set aTitle to | program-title | of bRec
–> "世界・ふしぎ発見!"

on trimStrFromTo2(aStr, fromStr, toStr)
  if fromStr is not equal to "" then
    set sPos to (offset of fromStr in aStr)
  else
    set sPos to 0
  end if
  
  
if sPos = 0 then
    return ""
  else
    set sPos to sPos + 1
  end if
  
  
if toStr is not equal to "" then
    set aLen to length of fromStr
    
set b to text (sPos + aLen) thru -1 of aStr
    
set ePos to (offset of toStr in b)
  else
    set ePos to length of aStr
  end if
  
set aRes to text 1 thru ePos of b
  
return aRes
end trimStrFromTo2

on makeRecordFromList(aList)
  set quotChar to (ASCII character 34)
  
  
set s_header to "return {"
  
set recList to {}
  
set s to ""
  
  
set itemCount to count aList
  
  
repeat with i from 1 to itemCount
    set j to ((contents of item 1 of item i of aList) as Unicode text)
    
if j contains ":" then
      set j to repChar(j, ":", "") of me
    end if
    
    
set aLabel to "| " & j & " |"
    
set aValue to ((contents of item 2 of item i of aList) as Unicode text)
    
set s to s & aLabel & ":" & quotChar & aValue & quotChar
    
if i is not itemCount then
      set s to s & ","
    end if
  end repeat
  
  
set s to s_header & s & "}"
  
set aRes to run script (s as Unicode text)
  
  
return aRes
  
end makeRecordFromList

–文字置換
on repChar(origText, targChar, repChar)
  set origText to origText as string
  
set targChar to targChar as string
  
set repChar to repChar as string
  
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/04 iEPGのファイルから各種情報を取り出してみるテスト v2

iEPGの録画予約ファイルを読み込んで、各種情報を取り出すAppleScriptの試作です。

iEPGのファイルをダウンロードしてみたところ、

–iEPGファイル サンプル ここから
Content-type: application/x-tv-program-info; charset=shift_jis
version: 1
station: テレビ朝日
year: 2010
month: 05
date: 10
start: 19:00
end: 19:54
program-title: もしものシュミレーションバラエティー お試しかっ![字]
genre: 144
subgenre: 8

日本最大のカレー専門チェーン店で帰れま10にチャレンジ!
ナインティナイン岡村隆史が初参戦で大活躍!?

–iEPGファイル サンプル ここまで

といった形式で書かれていたので、それぞれのラベル値の内容を取り出すようにしてみました。

とりあえず、「テレビ王国」と「ON TV」のiEPGファイルで試してみました。

スクリプト名:iEPGのファイルから各種情報を取り出してみるテスト v2
set anAlias to choose file
set aData to read anAlias
set aData to aData as Unicode text

–iEPGのデータから取り出すラベル値のリスト
set pList to {"Content-type:", "version:", "station:", "year:", "month:", "date:", "start:", "end:", "program-title:", "subgenre:", "genre:"}
set dList to {}

repeat with i in pList
  set j to contents of i
  
  
set aRes to trimStrFromTo2(aData, j, (ASCII character 13) & (ASCII character 10)) of me
  
if aRes is not equal to "" then
    set aRes to repChar(aRes, return, "") of me
  end if
  
  
set the end of dList to {j, aRes}
end repeat

dList
–> {{"Content-type:", "application/x-tv-program-info; charset=shift_jis"}, {"version:", "1"}, {"station:", "テレビ朝日"}, {"year:", "2010"}, {"month:", "07"}, {"date:", "03"}, {"start:", "21:00"}, {"end:", "22:51"}, {"program-title:", "土曜ワイド劇場「東京駅お忘れ物預り所4」[デ][字]"}, {"subgenre:", "1"}, {"genre:", "48"}}

on trimStrFromTo2(aStr, fromStr, toStr)
  if fromStr is not equal to "" then
    set sPos to (offset of fromStr in aStr)
  else
    set sPos to 0
  end if
  
  
if sPos = 0 then
    return ""
  else
    set sPos to sPos + 1
  end if
  
  
if toStr is not equal to "" then
    set aLen to length of fromStr
    
set b to text (sPos + aLen) thru -1 of aStr
    
set ePos to (offset of toStr in b)
  else
    set ePos to length of aStr
  end if
  
set aRes to text 1 thru ePos of b
  
return aRes
end trimStrFromTo2

–文字置換
on repChar(origText, targChar, repChar)
  set origText to origText as string
  
set targChar to targChar as string
  
set repChar to repChar as string
  
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/04 リストをレコードに v2

{ラベル値,データ}のペアになっているリストから、レコードを作成するAppleScriptです。{”aaa”,”123″}を{aaa:”123″}にします。

以前掲載したものは、文字列から動的にAppleScriptを作成して実行。ファイルに書き出しておいて、呼び出し側でデータを一時ファイルから読み取っていました。

ファイルI/Oを行う分だけスピードのロスがあったわけで、よくよく考えればファイルI/O経由でなくともダイナミックに組み立てたAppleScript側からレコードをreturnすればよいので、ファイルI/Oを使わないように書き換えたのと、最初に渡されたリストのラベル値の中にコロン(:)が入っていた場合に除去してから処理するようにしてみました。

スクリプト名:リストをレコードに v2
set aList to {{"Content-type:", "application/x-tv-program-info; charset=shift_jis"}, {"version:", "1"}, {"station:", "TBSテレビ"}, {"year:", "2010"}, {"month:", "07"}, {"date:", "03"}, {"start:", "21:00"}, {"end:", "21:54"}, {"program-title:", "世界・ふしぎ発見!『いい男はこうして生まれた!韓国ヒーローの秘密』[字]"}, {"subgenre:", "5"}, {"genre:", "96"}}
set bRec to makeRecordFromList(aList) of me
bRec
–> {| content-type |:"application/x-tv-program-info; charset=shift_jis", | version |:"1", | station |:"TBSテレビ", | year |:"2010", | month |:"07", | date |:"03", | start |:"21:00", | end |:"21:54", | program-title |:"世界・ふしぎ発見!『いい男はこうして生まれた!韓国ヒーローの秘密』[字]", | subgenre |:"5", | genre |:"96"}

on makeRecordFromList(aList)
  set quotChar to (ASCII character 34)
  
  
set s_header to "return {"
  
set recList to {}
  
set s to ""
  
  
set itemCount to count aList
  
  
repeat with i from 1 to itemCount
    set j to ((contents of item 1 of item i of aList) as Unicode text)
    
if j contains ":" then
      set j to repChar(j, ":", "") of me
    end if
    
    
set aLabel to "| " & j & " |"
    
set aValue to ((contents of item 2 of item i of aList) as Unicode text)
    
set s to s & aLabel & ":" & quotChar & aValue & quotChar
    
if i is not itemCount then
      set s to s & ","
    end if
  end repeat
  
  
set s to s_header & s & "}"
  
set aRes to run script (s as Unicode text)
  
  
return aRes
  
end makeRecordFromList

–文字置換
on repChar(origText, targChar, repChar)
  set origText to origText as string
  
set targChar to targChar as string
  
set repChar to repChar as string
  
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/03 ファイル名Aの拡張子を、ファイル名Bの拡張子に付け替える

ファイル名Aの拡張子を、ファイル名Bの拡張子に付け替えるAppleScriptです。

fn1.jpg

まず、1つのHTMLファイル(拡張子=.html)を選択。

fn2.jpg

次いで、JPEGファイル(拡張子=.jpg)を選択すると・・。

最初に選択したファイルの拡張子を、後で選択したファイルの拡張子に置き換えた文字列が得られます。お好みに応じて、実際にファイル名のリネームを行ったりするとよいかもしれません。

スクリプト名:ファイル名Aの拡張子を、 ファイル名Bの拡張子に付け替える
set aFile to choose file
set bFile to choose file

tell application “Finder”
  set aName to name of aFile –> iChatで文字チャットの相手に文字列を送信。長い場合にはzip圧縮して送信.html
  
set bName to name of bFile –> xcframew1.jpg
end tell

set cName to cnvExtFromAtoB(aName, bName) of me
–> “iChatで文字チャットの相手に文字列を送信。長い場合にはzip圧縮して送信.jpg”

–ファイル名Aの拡張子を、ファイル名Bの拡張子に付け替える
on cnvExtFromAtoB(aFileName, bFilename)
  set aExt to retExtNameFromFilenameStr(aFileName) of me
  
set bExt to retExtNameFromFilenameStr(bFilename) of me
  
set nFileName to repChar(aFileName, aExt, bExt) of me
  
return nFileName
end cnvExtFromAtoB

–ファイル名文字列から拡張子のみ取得する
on retExtNameFromFilenameStr(fileNameStr)
  set fLen to length of fileNameStr
  
set revText to (reverse of (characters of fileNameStr)) as string –逆順テキストを作成
  
set anOffset to offset of “.” in revText
  
set fRes to text (fLen - anOffset + 1) thru -1 of fileNameStr
  
return fRes
end retExtNameFromFilenameStr

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2010/07/03 iChatで文字チャットの相手に文字列を送信。長い場合にはテキストに書き出してzip圧縮して送信

iChatで文字チャットの相手に文字列を送信。長い場合にはテキストファイルに書き出してzip圧縮してそのファイルを送信するAppleScriptです。

iChat経由で何らかのコマンドのやりとりを行うような場合に、コマンドの実行結果が長い(実際に調査してみたら2419文字以上)場合にはiChatが送信をブロックするので、メッセージの送信が行えません。

そこで、2419文字以上の結果をiChat経由で送信する場合には、結果をテキストファイルに書き出してzip圧縮し、zipファイルを送り返すようにしてみました。

これなら、結果が長くなるような場合でも問題なく返信することができます。

iChatでメッセージの文字列を相手に送るのも、ファイルを相手に送るのも同じsendコマンドで行えます。

スクリプト名:iChatで文字チャットの相手に文字列を送信。長い場合にはzip圧縮して送信
–すでに文字チャットを開始していることが前提条件
set aPerson to getPersonOfChat1() of me

set aRes to do shell script “cd ~/usr/bin && ls -la” –ちょっとテスト用に長めの文字列を作ってみた

set aLen to length of aRes

if aLen > 2419 then –iChatの文字チャットで送信できる文字の最大数を確認したら、2419文字だった(Mac OS X 10.6)
  set aRes to makeZipFile(aRes) of me –メッセージ内容をテキストファイルに書き出してZip圧縮
  
set aRes to POSIX file aRes
end if

tell application “iChat”
  tell chat 1
    send aRes to aPerson –メッセージ(文字)もファイルも送信コマンドは同じ
  end tell
end tell

–Chat 1の相手を取得する
on getPersonOfChat1()
  tell application “iChat”
    tell chat 1
      set aPerson to participants
      
set aPerson to first item of aPerson
      
return aPerson
    end tell
  end tell
end getPersonOfChat1

–指定データをファイルに書き出してzip圧縮
on makeZipFile(aStr)
  set aPath to (path to temporary items from system domain) as string
  
set afN to (do shell script “uuidgen”) & “.txt”
  
  
set aFullPath to aPath & afN
  
write_to_file(aStr, aFullPath, false) of me
  
  
set f1Path to quoted form of POSIX path of aFullPath
  
set f2Path to quoted form of POSIX path of (aFullPath & “.zip”)
  
  
try
    with timeout of 3600 seconds
      set aRes to do shell script “zip -r -j “ & f2Path & ” “ & f1Path
    end timeout
  on error
    return false
  end try
  
  
return (POSIX path of (aFullPath & “.zip”))
end makeZipFile

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に