Archive for the 'フィルタ参照(filter reference)' Category

2015/07/13 ASOCでDict書き込み_3(Bridge Plus)

完全に趣味の内容のAppleScriptを、Shane Stanleyがアップデートして送ってくれました(汗)。趣味のScriptというのは、完全に作り捨てに近いというか、あまり後先考えずに作ってしまうことが多いですが・・・

書き換えポイントは、

 (1)ASObjcExtras.frameworkではなくBridgePlusライブラリを使用
 (2)NSFileManagerでディレクトリを作成
 (3)パスの組み立て時に「URLByAppendingPathComponent:」を使うことにより、フォルダを示すパスの末尾に「:」がついていなかったとか、「::」といった誤った表記を行ってしまった場合に備えている

とのこと。do shell scriptなんてダサいぜ、的なShaneのご意見もありましたが、使って簡潔になる箇所(dateコマンドとか)は使ってもいいんじゃないかと。いえ、意見はとってもわかるんですけど、「使えるものはなんでも使う派」なんで(^ー^;;

OS X 10.11ではaliasやfileとNSURLが正確にBridgeされるようになるので、パスの取り扱いについては機能向上(簡潔な記述)が期待ができそうです。”NSURL”を書くと予約語とぶつかる、とかいうダサダサな仕様が直ることは10.11に期待したいです。

しかし、英語圏のShaneから正確な日本語データの入ったプログラムが送られてくると(リスト内のリンクをクリックすればScript Editorに転送されるのはわかっているとはいえ)、かなりビビります(^ー^;;

AppleScript名:ASOCでDict書き込み_3(Bridge Plus)
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions
use script “BridgePlus” – instead of ASOBjCExtras framework

load framework – BridgePlus command to load

set a1List to {“msName”, “sortieTimes”}
set b1List to {{“近 装甲強化型ジム 獲得済 COST: 200″, 66}, {“遠 ジム・キャノン 獲得済 COST: 160″, 43}, {“近 ザクII(F2) 獲得済 COST: 160″, 42}, {“近 ジム・コマンド 獲得済 COST: 200″, 32}, {“近 ジム(WD隊) 獲得済 COST: 160″, 28}, {“近 陸戦型ガンダム 獲得済 COST: 220″, 24}, {“近 ジム改 獲得済 COST: 240″, 22}, {“遠 ガンタンク 獲得済 COST: 200″, 22}, {“格 ジム(指揮官機) 獲得済 COST: 160″, 20}, {“近 ジム 獲得済 COST: 120″, 19}, {“遠 量産型ガンタンク 獲得済 COST: 160″, 14}, {“格 陸戦型ジム 獲得済 COST: 120″, 12}, {“格 ガンダム 獲得済 COST: 280″, 11}, {“近 ジム・トレーナー 獲得済 COST: 120″, 9}, {“射 ジム・スナイパーII(WD隊) 獲得済 COST: 220″, 9}, {“射 陸戦型ガンダム(ジム頭) 獲得済 COST: 200″, 7}, {“格 ガンダムEz8 獲得済 COST: 240″, 6}, {“近 ジム・寒冷地仕様 獲得済 COST: 200″, 6}, {“狙 ジム・スナイパーカスタム 獲得済 COST: 200″, 6}, {“格 ジム・ストライカー 獲得済 COST: 180″, 4}, {“格 ガンキャノン重装型 獲得済 COST: 160″, 3}, {“近 アクア・ジム 獲得済 COST: 160″, 2}, {“射 ガンキャノン 獲得済 COST: 200″, 2}, {“近 ジム・コマンドライトアーマー 獲得済 COST: 160″, 1}, {“格 ボールK型 獲得済 COST: 120″, 0}, {“格 B.D.2号機 獲得済 COST: 260″, 0}, {“格 プロトタイプガンダム 獲得済 COST: 280″, 0}, {“近 パワード・ジム 獲得済 COST: 240″, 0}, {“射 デザート・ジム 獲得済 COST: 160″, 0}, {“遠 量産型ガンキャノン 獲得済 COST: 200″, 0}}

– BridgePlus uses SMSForder instead of SMSFord in ASOBjCExtras, but method is the same
set aArray to current application’s SMSForder’s subarraysIn:b1List asDictionariesUsingLabels:a1List |error|:(missing value)

set cRec to {msList:aArray, sortieDate:date string of (current date)}

set aName to “efsf.plist”
saveRecordToFolAsPlist(cRec, “戦場の絆”, aName) of me

on saveRecordToFolAsPlist(theRecord, folName, aName)
  
  
set myAppSupDir to POSIX path of (path to application support from user domain)
  
set folderURL to (current application’s class “NSURL”’s fileURLWithPath:myAppSupDir)’s URLByAppendingPathComponent:folName
  
  
–do shell script(mkdir -p)のかわりに、指定ディレクトリまで作成
  
current application’s NSFileManager’s defaultManager()’s createDirectoryAtURL:folderURL withIntermediateDirectories:true attributes:(missing value) |error|:(missing value)
  
  
set theDict to current application’s NSDictionary’s dictionaryWithDictionary:theRecord
  
set aRes to theDict’s writeToURL:(folderURL’s URLByAppendingPathComponent:aName) atomically:true
  
  
return aRes as boolean
  
end saveRecordToFolAsPlist

★Click Here to Open This Script 

2013/03/10 Safariで指定可能なユーザーエージェントのリストを返す

Safariでプリセットで選択可能なユーザーエージェントを取得するAppleScriptです。OS X 10.8.2+Safari 6.0.3上で動作確認しています。

GUI Scriptingを用いているので、あらかじめシステム環境設定の「アクセシビリティ」で「補助装置にアクセスできるようにする」のチェックを入れておいてください。

safari0.png

Safariの「環境設定」>「詳細」で、「メニューバーに”開発”メニューを表示」の項目のチェックをオンにしておくと、メニューバーに「開発」の項目が表示されるようになります(Macユーザーの一般常識)。

この「開発」メニューの「ユーザーエージェント」の下に、Safariがあらかじめ用意しているユーザーエージェントの選択メニューが表示されます。この項目を適宜選択すると、指定ユーザーエージェント名でWebサーバーにアクセスするようになります。

safari1.png

この、Safariがメニューから指定可能なユーザーエージェントの一覧を取得します。

safari2.png

Safariではプリセットのユーザーエージェント名以外にも、「その他」から適宜指定可能なので、別にプリセットのユーザーエージェント名にこだわる必要はありません。

スクリプト名:Safariで指定可能なユーザーエージェントのリストを返す

–Safariでメニューから指定可能なUser Agentのリストを取得する
set uaList to retEnableUserAgentFromSafari() of me
–> {”Safari 6.0.3 ― Mac”, “Safari 5.1.7 ― Windows”, “Safari iOS 5.1 ― iPhone”, “Safari iOS 5.1 ― iPod touch”, “Safari iOS 5.1 ― iPad”, “Internet Explorer 9.0″, “Internet Explorer 8.0″, “Internet Explorer 7.0″, “Google Chrome 19.0 ― Mac”, “Google Chrome 19.0 ― Windows”, “Firefox 11.0 ― Mac”, “Firefox 11.0 ― Windows”, “Opera 11.62 ― Mac”, “Opera 11.62 ― Windows”}

–Safariで指定可能なユーザーエージェントのリストを返す
on retEnableUserAgentFromSafari()
  
  
–除外リスト(This list is for Japanese environment. This depends on each localized menu item string)
  
set exList to {“デフォルト(自動選択)”, “その他…”}
  
  
–activate application “Safari”
  
tell application “System Events”
    tell process “Safari”
      
      
–開発メニューのイネーブルチェック
      
tell menu bar 1
        set tList to title of every menu bar item
      end tell
      
      
if “開発” is not in tList then –(This String is for Japanese environment. This depends on each localized menu item string)
        display dialog “開発メニューがオンになっていません” buttons {“OK”} default button 1 with icon 1
        
return
      end if
      
      
–「開発」>「ユーザーエージェント」
      
tell menu 1 of menu item 2 of menu 1 of menu bar item 8 of menu bar 1
        set t2List to title of every menu item whose title is not “” –セパレーター以外のメニュー項目を取得
      end tell
      
    end tell
  end tell
  
  
set t3List to {}
  
repeat with i in t2List
    set j to contents of i
    
if j is not in exList then
      set the end of t3List to j
    end if
  end repeat
  
  
return t3List
  
end retEnableUserAgentFromSafari

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

2013/02/21 指定フォルダ中のファイル名が拡張子を外すと衝突するかどうかチェック

指定フォルダ中のファイルから拡張子を外した状態で名称が衝突するかどうかチェックするAppleScriptです。

あるフォルダ(InDesign書類のパッケージ化したフォルダ中にあるLinksフォルダ)の中に入っている雑多な画像ファイル(EPSとかPhotoshopとかIllustrator書類とかいろいろ)をすべてJPEG画像に書き出すプログラムをさくっと作った……まではよかったのですが、処理を行うとエラー表示も出ないのに処理前の画像数と処理後の画像数が合わないという状態に。

さっそく、フォルダ内のファイル名一覧を取得して、Excelのシート上にペーストして見比べて……………「ファイル名が同じで拡張子だけが違う」というやっかいなファイルが存在していることに(自分以外の人が)気付きました。

folder1.png

前述の「処理前のファイル数と処理後のファイル数が合わない」という問題は、拡張子の部分以外のファイル名が重複しているファイルの両方ともが順次JPEGに変換されて、上書きされて先に処理したファイルが消されたために生じたものでした。

対処方法は「処理前に検出する」ことと「ファイルを書き込むときに迂回処理を行う」ことの2つ。

……簡単そうなのは前者だったので、作ってみたら割とすごいことに。すでにどこかで使ったルーチンのオンパレードですが、それなりの長さに。

# ファイル名の衝突迂回プログラムは実は作ってあったのですが……その存在を忘れていました。OS側がやっているのと同じく、存在確認しつつファイル名に子番号を(インクリメンタルに)付けていくというものです

指定フォルダ内のファイル名一覧を取得し、全ファイル名から拡張子を外した名称リストを作成。名称リスト内で重複がないかどうかをチェックします。

重複が存在していた場合には、

folder2.png

のように、どのファイルの組み合わせに問題があるかを一覧表示して終了します。

スクリプト名:指定フォルダ中のファイル名が拡張子を外すと衝突するかどうかチェック
set aFol to choose folder with prompt “フォルダを選択してください。”

set aFolStr to aFol as string

tell application “Finder”
  tell folder aFolStr
    set aList to name of every file
  end tell
end tell

–指定フォルダ内のファイル名の(拡張子を外した部分の)衝突判定を行う
set aRes to chkFileNameDuplicatesWithoutExtension(aList) of detectDupKit
if aRes is not equal to {} then
  
  
set dupList to {}
  
  
repeat with i in aRes
    set j to contents of i
    
tell application “Finder”
      tell folder aFolStr
        set aList to (name of every file whose name begins with j)
      end tell
    end tell
    
    
set the end of dupList to aList
    
  end repeat
  
  
set dup2List to FlattenList(dupList) of me
  
set firstItem to contents of first item of dup2List
  
choose from list dup2List default items {firstItem} with prompt “指定フォルダ中の以下のファイルは拡張子以外が同じため、後の処理でファイル名の衝突が起こります。
  
あらかじめどちらか一方を削除するか、片方の名前を変更するなどしておいてください。” with title “ファイル名の重複エラー”
  
  
return –終了
  
end if

script detectDupKit
  
  
–ファイル名リストをリスト型変数で渡すと、拡張子を外した名前で重複検出を行う
  
on chkFileNameDuplicatesWithoutExtension(aList)
    –拡張子を外す  
    
set aNList to {}
    
repeat with i in aList
      set j to contents of i
      
set the end of aNList to retFileNameWithoutExt(j) of me
    end repeat
    
    
–重複検出
    
set dupList to detectDuplicates(aNList) of me
    
if dupList = {} then return {}
    
    
–重複情報を単純なリストにして返す
    
set d2List to {}
    
repeat with i in dupList
      set j to contents of first item of i
      
set the end of d2List to j
    end repeat
    
    
return d2List
    
  end chkFileNameDuplicatesWithoutExtension
  
  
on removeDuplicates(aList)
    set newList to {}
    
repeat with i from 1 to (length of aList)
      set anItem to item 1 of aList
      
set aList to rest of aList
      
if {anItem} is not in aList then set end of newList to anItem
    end repeat
    
return newList
  end removeDuplicates
  
  
–ファイル名から拡張子を外す
  
on retFileNameWithoutExt(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 1 thru (fLen - anOffset) of fileNameStr
    
return fRes
  end retFileNameWithoutExt
  
end script

–与えられたリストの中で重複しているものをピックアップ。アルファベットの大文字小文字の違いを無視
on detectDuplicates(aList)
  set newList to {}
  
repeat with i from 1 to (length of aList)
    set tmpList to {}
    
    
–あえてアルファベットの大文字小文字の違いを無視(というよりも、同一視)
    
ignoring case
      set anItem to item 1 of aList
      
set aList to rest of aList
      
if {anItem} is in aList then set end of tmpList to anItem
      
repeat with j in aList
        set jj to contents of j
        
if jj = anItem then
          set end of tmpList to jj
          
exit repeat –重複は基本的にABC-abcのように1対のみという前提。フォルダ名の衝突回避が目的なので
        end if
      end repeat
    end ignoring
    
    
if tmpList is not equal to {} then
      set the end of newList to tmpList
    end if
  end repeat
  
return newList
end detectDuplicates

–By Paul Berkowitz
–2009年1月27日 2:24:08:JST
–Re: Flattening Nested Lists
on FlattenList(aList)
  set oldDelims to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {“????”}
  
set aString to aList as text
  
set aList to text items of aString
  
set AppleScript’s text item delimiters to oldDelims
  
return aList
end FlattenList

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

2013/02/02 USBメモリやネットワーク上のサーバーなどをアンマウント

USBメモリやネットワーク上のサーバーなどをアンマウントするAppleScriptです。

ファイルやディスクなどFinder上のオブジェクトに対してさまざまな操作をAppleScriptから行おうとしたら、「Finderというアプリケーション」に対して命令を出すことになります。

となると、当然のことながら「Finder」のAppleScript用語辞書を調べる必要があります。

finder1.png

AppleScriptエディタのツールバーで、「包含階層を表示」ボタンをクリック。

finder2.png

Applicationの下にdiskオブジェクトがあることが分ります。

finder3.png

とりあえず、ネットワーク上のサーバーやUSBメモリーを実際にマウントしてみて、プロパティを取得するなどアプリケーションと「対話」して調べてみましょう。ここでは、「3bai」という名前のUSBメモリーをマウント、そのプロパティを取得。

スクリプト名:3baiのプロパティを取得
tell application “Finder”
  properties of disk “3bai”
end tell

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

結果はこのようなものが得られました。

finder4.png

「ejectable」属性を見て、USBメモリーは判断できそうです。また、ネットワーク上のドライブ(ファイルサーバーとか、NASとか)であれば、「local volume」属性を見れば判定は可能です。

なので、おもむろに………

スクリプト名:USBメモリやネットワーク上のサーバーなどをアンマウント
tell application “Finder”
  eject (every disk whose ejectable is true) –外付けHDD, USBメモリー
  
eject (every disk whose local volume is false) –ネットワーク上のドライブ
end tell

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

こんな感じで、とくにエラートラップやタイムアウト時間の延長などは行っていませんが、素直に書くことができました。

ただし、これら外付けドライブ上のファイルをオープンしているアプリケーションが存在している場合に、ドライブのアンマウントが中断されてしまいますので、そのあたりは別の対策が必要になると思います。

2013/01/20 システムにインストールされているICC Profileのうち、指定キーワードに該当する名前を持つものでバージョン番号が最新のものを返す v2

システムにインストールされているICC Profileのうち、指定キーワードに該当する名前を持つもので、バージョン番号が最新のものをピックアップするAppleScriptです。

…………最初のものから、50行ぐらい短くなっています。

ICC Profileは/Library/ColorSync/Profilesとか、~/Library/ColorSync/Profilesなど複数箇所にインストール可能で、Mac OS Xが標準で用意しているものと、Adobeの各アプリがてんでバラバラにインストールしてお互いに互換性のないものなどが無造作に入っています。

Mac OS X 10.6でColorSync Scriptingが廃止になったときに、ICC Profileの管理機能はImage Eventsに移管されました(少し前からそうだったか、、、)。このImage Eventsに対してICC Profileの所在を問い合わせると、複数のインストール先にインストールされた同一名称のプロファイルが取得できたりするので、ユニーク化処理を行って重複分の消し込みを行っています。

スクリプト名:システムにインストールされているICC Profileのうち、指定キーワードに該当する名前を持つものでバージョン番号が最新のものを返す v2
–システムにインストールされているICC Profileのうち、指定キーワードに該当する名前を持つものでバージョン番号が最新のものを返す

set nList to getAProfile_(“Piyomaru Piyopiyo”)
set b to retLatestVersionICCprofileNameFromList_delExt_(nList)
–> “Piyomaru Piyopiyo V5.0.icc”

–キーワードを含む名称を持つICC Profileを取得する
on getAProfile_(aKeyword)
  
  
set unique_profile_names to {}
  
  
tell application “Image Events”
    
    
set all_profile_names to name of every profile whose name contains aKeyword
    
    
repeat with i from 1 to (count all_profile_names)
      set cur_profile_name to item i of all_profile_names
      
      
if cur_profile_name is not in unique_profile_names then
        set end of unique_profile_names to cur_profile_name
      end if
      
    end repeat
    
  end tell
  
  
return unique_profile_names
  
end getAProfile_

–与えられたICC Profileの名称リストからもっともバージョンの新しい(大きい)数字を持つものを返す
on retLatestVersionICCprofileNameFromList_delExt_(a)
  
  
–取り出した数値部分だけをキーにして降順ソート(大きな数→小さな数)
  
considering numeric strings
    set resList to shellSortDecending(a)
  end considering
  
  
return item 1 of resList
  
end retLatestVersionICCprofileNameFromList_delExt_

–シェルソートでリストを昇順ソート(入れ子ではないリスト)
on shellSortAscending(a)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item (j - h + 1) of a) > v)
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortAscending

–シェルソートでリストを降順ソート(入れ子ではないリスト)
on shellSortDecending(a)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item (j - h + 1) of a) < v)
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortDecending

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

2013/01/16 指定プロセスの死活判定 v2

指定プロセス(アプリケーション)がハングアップしているかどうかをUNIX的な見地と、AppleScript的な見地から判定するAppleScriptです。

以前掲載したバージョンでは、shellのpsコマンドだけで「クラッシュした」状態を検出していましたが、それだけでは不十分という話を書いていました。

そこで、2フェーズに分けて……

 フェーズ1:psコマンドでゾンビプロセスの確認
 フェーズ2:AppleScriptから指定アプリに名称確認

という確認をするようにしてみました。

これだけ丁寧にきめ細かく確認を行えば、たいていのクラッシュやハングアップ状態は検出できることでしょう(あいにく、Mac OS X上ではそんなに頻繁にそういう状態に遭遇していないので確認が難しいのですが)。ぜひ、いろいろなケースで試してみたいところです。

スクリプト名:指定プロセスの死活判定(Bundle IDで判定) v2
set aRes to detectAppAliveByID_(“com.apple.itunes”)
–> true (起動中、ゾンビ化していない)
–> false(起動していない)
–> “killed”(ゾンビ化していたので、killした)

–指定プロセスの死活判定(Bundle IDで判定)
on detectAppAliveByID_(aProcBundleID)
  set aProcBundleID to aProcBundleID as string
  
  
–Phase 1 psコマンド経由で状態を確認してみる
  
set aRes to false
  
try
    tell application “System Events”
      set aList to bundle identifier of every process
      
if aProcBundleID is in aList then
        
        
set tmpList to name of every process whose bundle identifier = aProcBundleID
        
set aProcName to contents of first item of tmpList
        
        
set aRes to true
        
tell process aProcName
          set processID to unix id –プロセスIDを取得
        end tell
        
        
set processID to processID as string
        
        
–指定プロセスがゾンビプロセス化しているかどうかを判定
        
set procState to (words of (do shell script “/bin/ps “ & processID & ” | cut -d ‘ ‘ -f 6″)) as string
        
        
if procState contains “Z” then
          –ゾンビプロセスを殺す
          
do shell script “/bin/kill -9 “ & processID
          
return “killed”
        end if
      else
        –指定したBundle IDのプロセスが存在しない場合falseでリターン
        
return false
      end if
    end tell
  on error
    –異常発生時にはさっさとリターン
    
return false
  end try
  
  
  
–Phase 2 指定アプリに直接コンタクトして反応を見る
  
try
    with timeout of 3 seconds
      tell application id aProcBundleID
        set aTmpvar to name –これができない(Scriptableな)アプリはほとんどないだろう(多分)
      end tell
    end timeout
  on error
    –名称を取得できなかった場合にはコケていると見なしてプロセスを殺す
    
do shell script “/bin/kill -9 “ & processID
    
return “killed”
    
  end try
  
  
  
return aRes
end detectAppAliveByID_

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

スクリプト名:指定プロセスの死活判定(アプリ名で判定) v2
set psRes to detectAppAliveByName_(“Safari”)
–> true (起動中、ゾンビ化していない)
–> false(起動していない)
–> “killed”(ゾンビ化していたので、killした)

–指定プロセスの死活判定(アプリ名で判定)
on detectAppAliveByName_(aProcName)
  set aProcName to aProcName as string
  
  
–Phase 1 psコマンド経由で状態を確認してみる
  
set aRes to false
  
try
    tell application “System Events”
      set aList to name of every process
      
if aProcName is in aList then
        set aRes to true
        
tell process aProcName
          set processID to unix id –プロセスIDを取得
        end tell
        
        
set processID to processID as string
        
        
–指定プロセスがゾンビプロセス化しているかどうかを判定
        
set procState to (words of (do shell script “/bin/ps “ & processID & ” | cut -d ‘ ‘ -f 6″)) as string
        
        
if procState contains “Z” then
          –ゾンビプロセスを殺す
          
do shell script “/bin/kill -9 “ & processID
          
return “killed”
        end if
      else
        –指定した名称のプロセスが存在しない場合falseでリターン
        
return false
      end if
    end tell
  on error
    –異常発生時にはさっさとリターン
    
return false
  end try
  
  
  
–Phase 2 指定アプリに直接コンタクトして反応を見る
  
try
    with timeout of 3 seconds
      tell application aProcName
        set aTmpvar to name –これができない(Scriptableな)アプリはほとんどないだろう(多分)
      end tell
    end timeout
  on error
    –名称を取得できなかった場合にはコケていると見なしてプロセスを殺す
    
do shell script “/bin/kill -9 “ & processID
    
return “killed”
    
  end try
  
  
return aRes
end detectAppAliveByName_

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

2013/01/12 最前面のアプリケーションをいったん終了させてから起動

最前面のアプリケーションをいったん終了させて、ふたたび起動させるAppleScriptです。

これは、コケかけているような怪しい状態のアプリケーションを対象としているものではなく、明確に動いているものを操作するためのものです。

画面の解像度を(狭い方に)変更したときに、フローティングパレットやフローティングウィンドウが隠れてしまうことがあります。その現象を解決するためにいったん終了させてふたたび起動するものです。とくに、アクティビティモニタのCPUの負荷メーターが見えなくなってしまう問題に対処するために作りました。

Script Menuに入れて呼び出して使っています。

スクリプト名:最前面のアプリケーションをいったん終了させてから起動
tell application “System Events”
  set aProc to every process whose frontmost is true
  
set aaProc to contents of first item of aProc
  
  
set aProp to properties of aaProc
  
  
set aBundleID to bundle identifier of aProp
  
end tell

tell application id aBundleID to quit

delay 1

tell application id aBundleID to launch

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

2013/01/12 指定プロセスの死活判定

指定プロセス(アプリケーション)がハングアップしているかどうかをUNIX的な見地から判定するAppleScriptです。

アプリ名称で指定して調べるものと、バンドルIDで指定して調べるものを用意してみました。

System Eventsで指定プロセス(アプリケーション)のプロパティを調べると、unix id(process id)を取得できます。このunix idで指定したプロセスの状態をpsコマンドで取得し、ゾンビプロセスになっているかどうかを判定します。

ただ……psコマンドで調べてゾンビプロセスに「なっていない」ものでも、GUI側から操作を試みても7色のビーチボールが回りっぱなしだったり、AppleScriptからの命令を受け付けないといった状態になっていることもままあります。

プロセス(アプリケーション)の死活判定はなかなか奥深いものがあります。実際には、psコマンドで調べるだけでなく、テストデータをオープンさせてみるとか、アプリケーションの名称を取得してみるとか、実行しても意味はないものの結果が得られるかどうかを調べてみるとよいでしょう。

スクリプト名:指定プロセスの死活判定(アプリ名で判定)
set psRes to detectAppAliveByName_(“Safari”)
–> true (起動中、ゾンビ化していない)
–> false(起動していない)
–> “killed”(ゾンビ化していたので、killした)

–指定プロセスの死活判定(アプリ名で判定)
on detectAppAliveByName_(aProcName)
  set aProcName to aProcName as string
  
  
set aRes to false
  
try
    tell application “System Events”
      set aList to name of every process
      
if aProcName is in aList then
        set aRes to true
        
tell process aProcName
          set processID to unix id –プロセスIDを取得
        end tell
        
        
set processID to processID as string
        
        
–指定プロセスがゾンビプロセス化しているかどうかを判定
        
set procState to (words of (do shell script “/bin/ps “ & processID & ” | cut -d ‘ ‘ -f 6″)) as string
        
        
if procState contains “Z” then
          –ゾンビプロセスを殺す
          
do shell script “/bin/kill -9 “ & processID
          
set aRes to “killed”
        end if
      else
        set aRes to false
      end if
    end tell
  on error
    set aRes to false
  end try
  
  
return aRes
end detectAppAliveByName_

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

スクリプト名:指定プロセスの死活判定(Bundle IDで判定)
set aRes to detectAppAliveByID_(“com.apple.safari”)
–> true (起動中、ゾンビ化していない)
–> false(起動していない)
–> “killed”(ゾンビ化していたので、killした)

–指定プロセスの死活判定(Bundle IDで判定)
on detectAppAliveByID_(aProcBundleID)
  set aProcBundleID to aProcBundleID as string
  
  
set aRes to false
  
try
    tell application “System Events”
      set aList to bundle identifier of every process
      
if aProcBundleID is in aList then
        
        
set tmpList to name of every process whose bundle identifier = aProcBundleID
        
set aProcName to contents of first item of tmpList
        
        
set aRes to true
        
tell process aProcName
          set processID to unix id –プロセスIDを取得
        end tell
        
        
set processID to processID as string
        
        
–指定プロセスがゾンビプロセス化しているかどうかを判定
        
set procState to (words of (do shell script “/bin/ps “ & processID & ” | cut -d ‘ ‘ -f 6″)) as string
        
        
if procState contains “Z” then
          –ゾンビプロセスを殺す
          
do shell script “/bin/kill -9 “ & processID
          
set aRes to “killed”
        end if
      else
        set aRes to false
      end if
    end tell
  on error
    set aRes to false
  end try
  
  
return aRes
end detectAppAliveByID_

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

2012/09/30 Mailで選択中のmessageの親フォルダのフルパスを文字で取得する

OS X 10.8標準装備のMail.app v6で、選択中のメッセージに対して、親フォルダのフルパスを文字で取得するAppleScript+動作確認用の呼び出し側Scriptです。

動作確認用に、「メール」アプリ上で選択中のメッセージが入っているフォルダのフルパスを取得し、そのフォルダ中に指定文字列を含むフォルダが存在するかどうかを確認するAppleScriptを書いてあります。ただし、あくまで動作確認用であり、本体部分は、

–与えられたmailboxのフルパスをテキストで返す
on getFullPath(mBox)

および、

–親フォルダを取得
on getParent(aMailBox)

の2つのサブルーチンです。getFullPathは10.8およびそれ以前のMac OS X(10.4あたりまで)に対応していますが、getParentは10.8にしか対応していませんね。本来、getParentもバージョン判定を行う必要があります。

mail_folder.png

スクリプト名:Mailで選択中のmessageの親フォルダのフルパスを文字で取得する
tell application “Mail”
  –先にSelectionを取得してみる
  
set aSelection to selection
  
if aSelection = {} then
    display dialog “Mail.app上でメールが選択されていません。” buttons {“OK”} default button 1 with icon note with title “ERROR”
    
return
  end if
  
  
–選択中のメールボックスを取得
  
tell message viewer 1
    set mbList to selected mailboxes
  end tell
  
  
–Selectionから情報を取得する処理
  
set anItem to item 1 of aSelection
  
set anItemProp to properties of anItem
  
set aStorage to mailbox of anItemProp
  
set aSubject to subject of anItemProp
  
  
  
set aRes to text returned of (display dialog “存在確認するフォルダ名称は?” default answer aSubject)
  
  
–すでに同一名称でフォルダが作成されていないか確認
  
tell aStorage
    ignoring case, diacriticals, hyphens, punctuation and white space
      set fList to every mailbox whose name contains aRes
    end ignoring
  end tell
  
  
set tmpFolObj to first item of fList
  
set tmpRes to getFullPath(tmpFolObj) of me
  
  
return tmpRes
  
end tell

–与えられたmailboxのフルパスをテキストで返す
on getFullPath(mBox)
  tell application “Mail”
    set aVer to version as number
    
    
set fullPath to name of mBox
    
    
repeat
      set mBox to getParent(mBox) of me
      
      
try
        set aClass to class of mBox
      on error
        exit repeat
      end try
      
      
if aVer 6 then
        –Mountain Lion搭載のMail 6.0以降の場合
        
if aClass is not equal to container then – ここを変更
          exit repeat
        end if
      else
        –それ以前の場合?
        
if aClass is not equal to mailbox then – ここを変更
          exit repeat
        end if
      end if
      
      
set aName to name of mBox
      
set fullPath to aName & “/” & fullPath
    end repeat
  end tell
  
  
return fullPath
end getFullPath

–親フォルダを取得
on getParent(aMailBox)
  tell application “Mail”
    tell aMailBox
      try
        set a to properties
        
set b to container of a
      on error
        return {“”, “”}
      end try
    end tell
  end tell
  
return b
end getParent

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

2012/08/22 指定フォルダ内のPDFの空白ページ以外を個別に取り出して別フォルダに保存 v3

指定フォルダ内のPDFの空白ページ「以外」を個別に取り出して、別フォルダに保存するAppleScriptです。

HTMLコンテンツを大量にプリンタで印刷するのに、HTMLレンダラー「wkpdf」を用いて個別のPDFに書き出し、これを連結してまとめてプリンタに送ろうとしたときに必要で作ったものです。

wkpdfでレンダリングしたときに余白ができて、内容が2ページ目まであふれていないのに空白の2ページ目が作られるケースがありました。これに対策すべく……

(1)PDFのページ数を数える。1ページのPDFなら、出力先フォルダにそのまま(ページ数を振りつつ)コピー

(2)2ページ以上のPDFなら、skimでPDFをオープンして、各ページに存在する文字情報を取得。2ページ目以降に文字情報が存在していない場合には、グラフィックが存在している可能性があるため、個別にPDFに書き出して、Photoshopでオープンし画像のヒストグラムを取得。画像のヒストグラムにドットの反応がなければ、「真っ白なページだった」=「空白ページ」とみなして破棄。ドットの反応があれば、出力先フォルダに(ページ数を振りつつ)コピー

という動作を行います。

この前のバージョンでは、2ページ目への文字あふれしか検出できていなかったのですが、改良してグラフィック要素があふれた場合でも対応できるようにしました。

実戦投入して、便利に使えています。

なお、おおきなおともだちの皆様にはお分かりと思いますが、Photoshop CS3以降でなくともPhotoshop Elements(お安い)でも代用できます。

スクリプト名:指定フォルダ内のPDFの空白ページ以外を個別に取り出して別フォルダに保存 v3
set inFol to choose folder with prompt “処理対象のPDFが入っているフォルダを指定”

set dtPath to choose folder with prompt “出力先フォルダを選択”
set dtPathStr to dtPath as string

tell application “Finder”
  tell folder inFol
    set aFileList to (every file whose name ends with “.pdf”) as alias list
  end tell
end tell

–それぞれのPDFの1ページ目のみ抽出
repeat with i in aFileList
  set j to contents of i
  
set pNum to pdfCount(j) of me
  
if pNum = 1 then
    –ファイルをコピー、ファイルのリネーム?
    
tell application “Finder”
      set fRes to duplicate j to dtPath
      
set tmpName to name of fRes
      
      
set bName to retFileNameWithoutExt(tmpName) of me
      
set cName to bName & “_1.pdf”
      
      
set name of fRes to cName
    end tell
    
    
  else if pNum > 1 then
    –1ページ目以外のページを、空白でないかどうかチェックする
    
set outList to {1}
    
    
repeat with ii from pNum to 2 by -1
      set aRes to detectBlankPageFromPDF(j, ii) of me
      
if aRes = false then
        set the end of outList to ii
      end if
    end repeat
    
    
    
–空白でないページのみ切り出して出力
    
repeat with ii in outList –出力対象ページ番号が入ったリスト
      set jj to contents of ii
      
set aRes to trimPDFbyPage(j, dtPathStr, jj) of me –エラー時にはfalseが返る
      
    end repeat
    
    
  end if
end repeat

–PDFの指定ページのみトリミング
on trimPDFbyPage(aFile, outFol, pageNum)
  tell application “Skim”
    close every document
    
    
open aFile
    
    
tell document 1
      set cCount to count every page
      
if cCount < pageNum then return false
    end tell
    
    
tell document 1
      set aProp to properties
      
set aRes to info of aProp
      
set aName to file name of aRes
      
set bName to retFileNameWithoutExt(aName) of me
      
      
set cName to bName & “_” & (pageNum as string) & “.pdf”
      
      
tell page pageNum
        set bList to bounds
        
set anImage to grab for bList –type “PDF”
      end tell
    end tell
    
    
set target_file to outFol & cName
    
write_to_file(anImage, target_file, false) of me
    
    
close every document
    
  end tell
end trimPDFbyPage

–ファイル名から拡張子を外す
on retFileNameWithoutExt(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 1 thru (fLen - anOffset) of fileNameStr
  
return fRes
end retFileNameWithoutExt

–指定PDFのページ数をかぞえる
on pdfCount(aPDF)
  return ((do shell script (“ruby -e \”require ‘osx/cocoa’;include OSX;require_framework ‘Quartz’;print PDFDocument.alloc.initWithURL(NSURL.fileURLWithPath(” & (quoted form of POSIX path of aPDF) & “)).pageCount\”")) as number)
end pdfCount

on makeFN(aNum, aDigit)
  set aText to “00000000000″ & (aNum as text)
  
set aLen to length of aText
  
set aRes to text (aLen - aDigit) thru -1 of aText
  
return aRes
end makeFN

–ファイルの追記ルーチン「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

–指定PDFの指定ページが空白(真っ白)かどうか判定する
on detectBlankPageFromPDF(aFile, targPage)
  tell application “Skim”
    close every document
    
    
open aFile
    
    
tell document 1
      set cCount to count every page
      
set cDigit to length of (cCount as string)
      
      
set docName to name
      
      
tell page targPage
        set bList to bounds
      end tell
      
      
if cCount > 1 then
        
        
–指定ページに文字が存在するかチェック
        
tell page targPage
          set aProp to properties
          
set aText to first item of text of aProp
        end tell
        
        
if aText is not equal to “” then
          return false
        end if
      end if
      
      
tell page targPage
        set anImage to grab for bList –type “PDF”
      end tell
    end tell
    
    
close every document
    
  end tell
  
  
–指定ページ内容をテンポラリフォルダに書き出す
  
set outFol to (path to temporary items from system domain) as string
  
set docName to (do shell script “/usr/bin/uuidgen”) & “.pdf”
  
  
set target_file to outFol & docName
  
write_to_file(anImage, target_file, false) of me
  
  
do shell script “sync” –キャッシュされたままディスクに書かれていないことがあるので実行
  
  
  
–書き出したPDFをPhotoshopでオープンしてヒストグラムから描画物の存在を検出
  
–Photoshop Elementsでも代用可
  
tell application “Adobe Photoshop CS3″
    close every document saving no
    
open file target_file
    
tell current document
      set aList to histogram
    end tell
    
close every document saving no
  end tell
  
  
–テンポラリPDFを削除する
  
do shell script “/bin/rm -f “ & (quoted form of POSIX path of target_file)
  
  
set aRes to detectWhiteFromList(aList) of me
  
  
return aRes –空白だとtrueを、そうでない場合にはfalseを返す
  
end detectBlankPageFromPDF

–与えられたPhotoshopヒストグラム(256段階の明るさのピクセル数)から、その内容が真っ白かどうかを検出
on detectWhiteFromList(aList)
  set aLen to length of aList
  
  
set zeroF to true
  
repeat with i from 1 to (aLen - 1) –真っ白かどうかを検知している
    if item i of aList is not equal to 0 then
      set zeroF to false
      
exit repeat
    end if
  end repeat
  
  
return zeroF
  
end detectWhiteFromList

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

2012/04/29 Terminalで全Window中の全Tabのうち、指定タイトルのものをクローズする

Terminal.appの全Window内のTabのうち、指定タイトルのものをクローズするAppleScriptです。

Mac OS X 10.7上のTerminalの各ウィンドウには、任意のタイトルを指定できるようになっています。Mac OS X 10.6上では、カスタマイズしたタイトルについてはAppleScriptからは参照するだけでした。

term00.jpg

スクリプト名:teminal.appでtabを操作する
tell application “Terminal”
  tell window 1
    tell tab 1
      set custom title to “ぴよまる”
    end tell
    
    
tell tab 2
      set custom title to “ぴよぴよ”
    end tell
    
  end tell
end tell

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

term01.jpg

term3.jpg

Tabのクローズについては、Window内のTabを指定してclose命令を実行してみても、クローズはできない状況です。GUI Scriptingで行うのもアレなので(最前面に持ってこないと実行できないというのは、ちょっとめんどう)、別の方法でクローズを実現することに。

Terminal.appの環境設定で、シェル終了後にWindowをどうするか指定することができます。

term1.jpg

term4.jpg

「ウィンドウを閉じる」「シェルが正常終了した場合には閉じる」「ウィンドウを閉じない」の3つから選択可能。

term2.jpg

これを「ウィンドウを閉じる」に設定しておき、指定Tabに「exit」コマンド(シェルコマンド)を送ることで、指定Tabをクローズできるようになります。

まあそんなわけで、Tabのカスタム名称を文字列で指定して該当するTabをすべてクローズできるようになったわけですが、これがどの程度有用かは…………ちょっと分かりません。

スクリプト名:Terminalで全Window中の全Tabのうち、指定タイトルのものをクローズする
set targTabTitle to “ぴよまる”

tell application “Terminal”
  set tabRef to a reference to (every tab of every window whose custom title is equal to targTabTitle)
  
  
repeat with i in tabRef
    do script “exit” in i
  end repeat
  
end tell

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

2012/03/24 インストールされているアプリのAS辞書を書き出すv2

2012/03/12 Find same file name with different extension in same directory

This is a simple AppleScript to find same file name with different extension in same directory.

Sample Data:
finder1.jpg

Output Data:
–> {{”D120_a.jpg”, “D120_a.png”}, {”D120_c.gif”, “D120_c.jpg”, “D120_c.png”, “D120_c.txt”}}

スクリプト名:find same file name with different extension in same directory
–Speed up technic
script aRef
  property aList : {} –every file name of user selected folder ( work)
  
property bList : {} – every file name list (without duplicates) (work)
  
property cList : {} –duplicated file name list (work)
  
property dList : {} –output duplicated file names with different extensions
end script

–Initialize variables
set aList of aRef to {}
set bList of aRef to {}
set cList of aRef to {}
set dList of aRef to {}

set a to choose folder with prompt “Choose check Folder”

tell application “Finder”
  tell folder a
    set aList of aRef to name of every file
  end tell
end tell

–make pure file name list(without extension) to cList
repeat with i in aList of aRef
  set j to contents of i
  
set jj to retFileNameWithoutExt(j) of me
  
  
if jj is in bList of aRef then
    –duplicated file name & does not exist in cList
    
if jj is not in cList of aRef then
      set the end of cList of aRef to jj
    end if
    
    
set tmpName to jj & “.”
    
    
tell application “Finder”
      tell folder a
        –set dList of aRef to dList of aRef & (name of every file whose name starts with tmpName)
        
set the end of dList of aRef to (name of every file whose name starts with tmpName)
      end tell
    end tell
    
  end if
  
  
set the end of bList of aRef to jj
end repeat

–Remove duplicates from List
set aRes to removeDuplicates(dList of aRef) of me

–> {{”D120_a.jpg”, “D120_a.png”}, {”D120_c.gif”, “D120_c.jpg”, “D120_c.png”, “D120_c.txt”}}

–Remove Duplicated Item from List
on removeDuplicates(aList)
  set newList to {}
  
repeat with i from 1 to (length of aList)
    set anItem to item 1 of aList
    
set aList to rest of aList
    
if {anItem} is not in aList then set end of newList to anItem
  end repeat
  
return newList
end removeDuplicates

–delete extension from file name
on retFileNameWithoutExt(fileNameStr)
  set fLen to length of fileNameStr
  
set revText to (reverse of (characters of fileNameStr)) as string –make reversed string
  
set anOffset to offset of “.” in revText
  
set fRes to text 1 thru (fLen - anOffset) of fileNameStr
  
return fRes
end retFileNameWithoutExt

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

2012/03/07 InDesign CS3で指定のオプジェクトを、JPEG書き出ししてiPhoneへ

InDesign CS3上で指定したオブジェクトをJPEG書き出ししてiPhoneに転送するAppleScriptです。

ことのはじまりは、目下開発中のiPhoneアプリ(私はプロジェクト管理やら仕様書書きやらを)で、Welcome画面の表示を行うのに「文字詰めや行送りをいろいろ指定できないと!」という話になったこと。

……そもそも、iPhoneの文字表示部品に、そんな気の利いたものはありません。そこで、InDesignやらIllustrator上で気の済むまで行間や文字間にこだわっていただいて、それをそのまま「画像」として書き出して表示しようではないか、と。

ただし、その指定内容をすぐにiPhoneの実機で見たいという話に。

その場で10分もかけずにInDesign書類上の指定レイヤー(「コンテンツ」)上に存在する指定名称(スクリプトラベル「screen」)のグループをJPEG書き出しして、書き出したJPEG書類をiPhotoにインポートして、iTunesに命令して接続しているすべてのiOSデバイスにシンクロを行うようAppleScriptで指令を出すようにしてみました。

できた瞬間はかなりガッツポーズでしたが、冷静に考えるとInDesignから書き出されるJPEG画像のクオリティが「残念なレベル」です。また、シンクロが終わるまでにちょっと時間がかかるので、実用性がいまひとつ。

結局、Good Reader for iPhoneをインストールして、iTunes経由でGood Readerに対してInDesignから書き出したPDFを渡す、という方法に落ち着きました。本Scriptは何らかの「可能性」を感じさせてくれはしたのですが、結局おクラ入りに。

スクリプト名:InDesign CS3で指定のオプジェクトを、JPEG書き出ししてiPhoneへ
–v1 InDesign CS3から直接JPEG書き出し。画像クオリティが低くて難あり

set dtPath to (path to desktop) as string
set fName to do shell script “date +%Y%m%d%H%M%S”

set fullPath to dtPath & fName & “.jpg”
set fullPathPOSIX to POSIX path of fullPath

tell application “Adobe InDesign CS3″
  tell document 1
    tell layer “コンテンツ”
      set aList to every group whose label is equal to “screen”
    end tell
    
    
set expItem to contents of first item of aList
    
export expItem format JPG to fullPath without with grids
    
  end tell
end tell

–iPhotoに書き出したJPEGファイルをインポートする
tell application “iPhoto”
  import from fullPathPOSIX
end tell

–アップデート可能なiOSデバイスをアップデートする
tell application “iTunes”
  repeat with i in sources
    if (kind of i is iPod) then update i
  end repeat
end tell

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

2012/02/07 iTunesのMobileアプリをコピーしてすべて展開する

このAppleScriptは、iTunesに入っているiPhone/iPadのアプリを指定フォルダにコピーして、アーカイブを展開して、さらにアプリケーションバンドルを「ただのフォルダ」に変えるものです。

iTunesをコントロールして、iOSアプリの情報を取得しようとしても……iTunes上でアプリの情報を取得するための機能は(iTunesのAppleScript用語辞書には)一切用意されていません(selectionすら取得できないのには意図的なものを感じる)。でも、アプリの情報にアクセスするのに、iTunesの力は必要ありません。ファイル・アクセスだけで十分です。

iosap1.jpg

iOSのアプリは拡張子「.ipa」のファイルであり、このファイルはZipアーカイブの拡張子を変えただけのものなので、簡単に展開できます。

iosap2.jpg

展開すると「Payload」フォルダ内にiOSアプリケーションが展開されます。さらに、このiOSアプリの拡張子「.app」を外します。

iosap3.jpg

iOSアプリのアプリケーションバンドル中に入っている各種データをSpotlightでキーワード検索して探し出すことが可能になります。

iosap4.jpg

一度走らせれば一括処理できるので、2度目を実行する必要性はかなり低いのですが……。処理が簡単で、GUIアプリをコントロールしていないですし、処理を行ったMacBook Proでは4コアのCPUのほとんどが空いており……並列処理にはもってこいの内容です(が、使い捨ての処理なのでそこまでは……)。

とりあえず、EULAの文章などのサンプルを取り出すために、他の用件を片付けている間にAppleScriptを走らせて処理できました。予想外だったのは、すべてのアプリのアーカイブを展開したら容量が増えてHDDの空き容量が減って危ない目に……。

スクリプト名:iTunesのMobileアプリをコピーしてすべて展開する
–iTunesのデータフォルダを求める
set mFol to path to music folder
set mFolStr to mFol as string
set mFolStr to mFolStr & “iTunes:Mobile Applications:”

–home:Music:iTunes:Mobile Applicationsフォルダ内のipaファイルの一覧を取得する
try
  tell application “Finder”
    tell folder mFolStr
      set appList to (every file whose name ends with “.ipa”) as alias list
    end tell
  end tell
on error
  display dialog “Mobile Applicationsフォルダが存在しないか、Mobileアプリが存在しません。” buttons {“OK”} default button 1 with icon 1
  
return
end try

–ipaファイルを処理するループ
set appProcTmp to choose folder with prompt “iOSアプリケーションを展開する作業フォルダを指定”

set aCount to 1 –フォルダ名のカウンタ

repeat with i in appList
  –ipaからzipにリネーム
  
set j to contents of i
  
  
tell application “Finder”
    
    
–新規フォルダ作成
    
set newFolder to (make new folder at appProcTmp with properties {name:aCount as string})
    
set newFolder to newFolder as alias
    
    
–ipaファイルをコピー
    
set anAppFile to (duplicate j to newFolder)
    
set anAppFile to anAppFile as alias
    
    
–ipaファイルをzipにリネーム
    
set aName to name of anAppFile
    
set bName to retNameFromFilenameStr(aName) of me
    
set bName to bName & “.zip”
    
    
set name of anAppFile to bName –rename
    
  end tell
  
  
–unzipを実行してzipアーカイブを展開
  
set tmpFolPath to POSIX path of newFolder
  
set tmpPathPOSIXfull to POSIX path of anAppFile
  
try
    do shell script “cd “ & quoted form of tmpFolPath & ” && unzip “ & quoted form of tmpPathPOSIXfull
  on error erMes
    return {false, erMes}
  end try
  
–展開ここまで
  
  
  
–展開後のアプリケーションバンドルをただのフォルダに変える
  
tell application “Finder”
    tell folder (newFolder as string)
      tell folder “Payload”
        set appFileList to (every file whose name ends with “.app”)
        
set appFile to (contents of first item of appFileList) as alias
        
        
set tmpName to name of appFile
        
set newAppName to retNameFromFilenameStr(tmpName) of me
        
set name of appFile to newAppName
      end tell
    end tell
  end tell
  
  
  
set aCount to aCount + 1
  
end repeat

–ファイル名文字列から拡張子を外して返す
on retNameFromFilenameStr(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 1 thru (fLen - anOffset) of fileNameStr
  
return fRes
end retNameFromFilenameStr

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

2012/01/05 文字入力モードを制御

GUI Scripting経由でSystemUIServerを制御して、IMの文字入力モードを変更するAppleScriptです。

実行には、GUI Scriptingがオンになっている必要があります。また、現時点ではMac OS X 10.6.8と10.7.2で確認してある状態です(10.5は微妙。10.4ではダメだと思います)。

→ 後日確認したところ、Mac OS X 10.5.8と10.4.11では動きませんでした。予想どおり。

文字入力モードをAppleScriptからコントロールするのは、普通に考えれば無理そうです。

真っ先に思いつくのが、AppleScriptObjCによるGUIつきアプリケーションを作成して、そのアプリケーションのWindow上にNSTextFieldを作成し、入力文字種類を制御するやりかたです。これなら、文字入力を制御できているといえなくもありません。

サードパーティのIMまで目を向けると、ジャストシステムのATOKはATOKダイレクトAPIなるAPIをユーザーに公開しており、コントロールできなくもなさそうな雰囲気はしているのですが、メーカーが想定している使い方しかさせてもらえなさそうな雰囲気も漂っています。

AppleScriptObjC経由で、ことえりのステータスを変更ないしは固定するようなプログラムを呼び出す方法も考えられなくもないですが……すぐには情報が見つかりませんでした。

そこで、きわめてAppleScript的に、GUI Scripting経由でコントロールしてみようということになりました。

画面上部のメニュー右側に表示されるMenu Extraは、SystemUIServerというプログラムが管轄しています(Mac OS X 10.6/10.7)。

menu1.jpg

このため、SystemUIServerのメニューの各アイテムにAppleScriptからアクセスすると、最低限、どのような内容を表示しているか取得できそうです。ユーザーによってMenu Extraの内容や並び順はカスタマイズされまくっているので、Menu Extra同士の識別ができなくてはなりません。

descriptionという属性を調べることで、どのプログラムが表示しているものか識別できそうです。Apple純正のMenu Extraしか値を取得できていない状態ですが、今回の目的のためにはこれで十分です。

並び順からいって、「text input」というのがIMのMenu Extraを表しているようです。

スクリプト名:System UI Serverから何がmenu extraを表示しているかを取得
activate application “SystemUIServer”
tell application “System Events”
  tell process “SystemUIServer”
    tell menu bar 1
      set aList to description of every menu bar item
    end tell
  end tell
end tell
–> {”time machine”, “bluetooth”, “iChat”, “displays”, “AirMac Menu Extra”, “システムサウンド音量”, “AppleScript”, “バッテリーメニュー。 完全充電まで 5 時間 39 分 .”, “clock”, “text input”, “user”}

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

次に、どのプログラムがどのような情報を表示しているのか「value」属性を調べてみました。「英字」「ひらがな」「カタカナ」といった情報が取得できます。けっこういい感じです。

スクリプト名:System UI Serverから各menu extraが何を表示しているかを取得
activate application “SystemUIServer”
tell application “System Events”
  tell process “SystemUIServer”
    tell menu bar 1
      set aList to value of every menu bar item
    end tell
  end tell
end tell
–> {missing value, missing value, missing value, missing value, “Extreme net の 4 本のうち 4 本の信号”, missing value, missing value, missing value, “1月4日(水) 23:49″, “英字”, missing value}

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

ちなみに、このvalueをAppleScriptから変更できないか試してみたのですが、valueはあくまで現状を反映させたものであり、書き換えてみても何も起きませんでした。

そこで、これまたGUI Scripting的なアプローチで、この「text input」のmenu extraをクリックして、表示されたメニューから指定のアイテムをクリックするという操作を行ってみました。

スクリプト名:System UI Serverを操作してIMの文字入力状態を変更する

setInputState(“英字”) of me
–setInputState(”ひらがな”) of me

–IMの入力状態を設定する
on setInputState(aState)
  activate application “SystemUIServer”
  
tell application “System Events”
    tell process “SystemUIServer”
      tell menu bar 1
        set aList to every menu bar item whose description is “text input”
        
set anItem to first item of aList
        
set curVal to value of anItem
        
        
if aState = curVal then return –変更の必要がなければリターン
        
        
tell anItem
          click
          
tell menu 1
            set mList to every menu item whose title is aState
            
set m1Item to first item of mList
            
tell m1Item
              click
            end tell
          end tell
        end tell
        
      end tell
    end tell
  end tell
  
end setInputState

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

人間、やればできるもんです。できないかと思っていたのですが、やってみたら案外手軽にできてしまいました。

ただし、複数のIMがインストールされている環境では、それぞれを識別するのはちょっと難しそうで……

menu2.jpg

もうちょっと調べてみないとなんともいえないところでしょうか。

2011/12/21 miで選択中の内容をファイルに書き出してperlのプログラムとしてterminalで実行 v2

miの最前面のドキュメント上で選択中のテキストをファイルに書き出して、perlのプログラムとしてTerminalで実行するAppleScriptのバグ修正版です。

最初のバージョンでは、改行コードがCRの状態で書き出されていたため、改行コードをLFに置換してから実行するようにしました。

初版では、選択範囲にコメント行が含まれているとエラーになっていたりしましたが、このバージョンではそういうことはありません。

スクリプト名:miで選択中の内容をファイルに書き出してperlのプログラムとしてterminalで実行 v2
tell application “mi”
  tell front document
    set this_data to selection
    
    
–エラー対策
    
if this_data = “” then
      display dialog “文字列が何も選択されていません” buttons {“OK”} default button 1 with icon 1 with title “エラー”
      
return
    end if
    
    
set this_data to this_data as Unicode text
    
  end tell
end tell

–改行コードがCRになっている部分をLFに置換(v2で追加)
set this_data to repChar(this_data, ASCII character 13, ASCII character 10) of me

set tmpPath to path to temporary items from user domain
set fStr to (do shell script “date +%Y%m%d%H%M%S”) & “.pl”
set fPath to (tmpPath as string) & fStr

write_to_fileUTF8(this_data, fPath, false) of me
do shell script “sync”

set sText to “perl -w “ & quoted form of POSIX path of fPath
doComInTerminalWindow(sText) of me

on doComInTerminalWindow(aCMD)
  tell application “Terminal”
    set wCount to count (every window whose visible is true)
    
    
– By wayne melrose
    
– Re: New window in Terminal.app
    
    
if wCount = 0 then
      –ウィンドウが1枚も表示されていない場合
      
do script aCMD
    else
      –すでにウィンドウが表示されている場合
      
do script aCMD in front window
    end if
  end tell
end doComInTerminalWindow

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_fileUTF8(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 as «class utf8» 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_fileUTF8

–文字置換ルーチン
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

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

2011/12/18 miで選択中の内容をファイルに書き出してperlのプログラムとしてterminalで実行

miでオープン中の最前面のドキュメントで選択中のテキストを書き出して、Terminalでperlのプログラムとして実行するAppleScriptです。

コメント行を含む内容を実行するとエラーになるのはなぜなんでしょう?(Perl詳しくないもんで)

mi21.jpg

mi11.jpg

スクリプト名:miで選択中の内容をファイルに書き出してperlのプログラムとしてterminalで実行
tell application “mi”
  tell front document
    set this_data to selection
    
    
–エラー対策
    
if this_data = “” then
      display dialog “文字列が何も選択されていません” buttons {“OK”} default button 1 with icon 1 with title “エラー”
      
return
    end if
    
    
set this_data to this_data as Unicode text
    
  end tell
end tell

–set this_data to “print ‘test’;”

set tmpPath to path to temporary items from user domain
set fStr to (do shell script “date +%Y%m%d%H%M%S”) & “.pl”
set fPath to (tmpPath as string) & fStr

write_to_fileUTF8(this_data, fPath, false) of me
do shell script “sync”

set sText to “perl -w “ & quoted form of POSIX path of fPath
doComInTerminalWindow(sText) of me

on doComInTerminalWindow(aCMD)
  tell application “Terminal”
    set wCount to count (every window whose visible is true)
    
    
– By wayne melrose
    
– Re: New window in Terminal.app
    
    
if wCount = 0 then
      –ウィンドウが1枚も表示されていない場合
      
do script aCMD
    else
      –すでにウィンドウが表示されている場合
      
do script aCMD in front window
    end if
  end tell
end doComInTerminalWindow

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_fileUTF8(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 as «class utf8» 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_fileUTF8

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

2011/12/06 現在表示中のCanvasに存在しているラインのうち青いものに影を付ける

OmniGraffleで、現在表示中のCanvasに存在しているラインのうち青いものだけに影を付けるAppleScriptです。

矢印だけに影を付けるとか、さまざまなフィルター参照が使えると便利なことでしょう。

スクリプト名:現在表示中のCanvasに存在しているラインのうち青いものに影を付ける
tell application “OmniGraffle 5″
  tell canvas of front window
    tell (every line whose stroke color is equal to {0.0, 0.0, 1.0}) –フィルタ参照で青いものだけ抽出
      set draws shadow to true
    end tell
  end tell
end tell

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

2011/08/21 特定の語句を含むMail.appのフォルダ(mailbox)を抽出してフルパスを文字列化

Mail.app上で特定のキーワードを含むフォルダを探し出して、そのパスを一覧表示するAppleScriptです。

Mail.app上で、フォルダを作ってメールの整理をしている場合に、ある特定のキーワードを含むフォルダがどこに存在しているかを検索したくなることがあります。しかし、Mail.appにそういう機能は存在していません。

acs0.jpg

なければ作るまでで……AppleScriptで作り出して、フルパス表示用に作っておいたサンプルと合わせて所要時間5分ぐらいでしょうか。

Mail.appではフォルダ(mailbox)をフィルタ参照で抽出できるので、思いっきり楽でした。自分のメイン環境ではフォルダが1万6000個ぐらい存在(自動で作成させているので)しているのですが、個数のカウントも1秒かからない程度(MacBook Pro 2010 Core i7 2.66GHz)でした。

実際、本Scriptでもフォルダ(mailbox)のフィルタ参照による抽出はすぐに終わるのですが、フルパスをテキスト化するのに処理時間のほとんどの時間がかかっています。

acs1.jpg

acs2.jpg

本Scriptを早急に作る必要が出てきたのは……メールの整理中に間違えて「Accessibility Dev」MLのフォルダを捕まえてどこかにドロップしてしまって、フォルダが多すぎてどこに落としたか分からなくなってしまったためです。マウスを使っている場合には起こらない悲劇、、、

スクリプト名:特定の語句を含むMail.appのフォルダ(mailbox)を抽出してフルパスを文字列化
set searchKeyword to “AppleScript”

tell application “Mail”
  –特定キーワードを名前に含むフォルダ(mailbox)を抽出
  
set allPath to every mailbox whose name contains searchKeyword
  
  
–与えられたフォルダ
  
set bList to {}
  
repeat with i in allPath
    set the end of bList to getFullPath(i) of me
  end repeat
  
  
–結果の一覧表示
  
choose from list bList with prompt “検索結果:”
  
end tell

–与えられたmailboxのフルパスをテキストで返す
on getFullPath(mBox)
  tell application “Mail”
    set fullPath to name of mBox
    
    
repeat
      set mBox to getParent(mBox) of me
      
      
try
        set aClass to class of mBox
      on error
        exit repeat
      end try
      
      
if aClass is not equal to mailbox then
        exit repeat
      end if
      
      
set aName to name of mBox
      
set fullPath to aName & “/” & fullPath
    end repeat
  end tell
  
  
return fullPath
end getFullPath

–親フォルダを取得
on getParent(aMailBox)
  tell application “Mail”
    tell aMailBox
      try
        set a to properties
        
set b to container of a
      on error
        return {“”, “”}
      end try
    end tell
  end tell
  
return b
end getParent

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