Archive for the 'System Events' Category

2016/11/29 バンドル形式のAppleScript自身の「説明」を取得する v3

バンドル形式のAppleScript自身に書かれている「説明」の文章を取得するAppleScriptです。

path to meで自分自身のパスを取得したあと、ファイルタイプ(type identifier)を問い合わせるように変更しました。

AppleScript名:バンドル形式のAppleScript自身の「説明」(description.rtfd/TXT.rtf)を取得する v3
【コメント】 このScriptの説明文を書いておきますよー
– Created 2016-10-12 by Takaaki Naganoya
– Created 2016-11-28 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
–http://piyocast.com/as/archives/4268

set cRes to retMyComment() of me
–> "このScriptの説明文を書いておきますよー"

on retMyComment()
  set myPath to (path to me)
  
tell application "System Events"
    set myType to type identifier of myPath
  end tell
  
if myType is not equal to "com.apple.applescript.script-bundle" then return ""
  
  
set docPath to (myPath as string) & "Contents:Resources:description.rtfd:TXT.rtf"
  
set aRes to retTextFromRTF(docPath) of me
  
return aRes
end retMyComment

on retTextFromRTF(aFile)
  set aFilePath to current application’s NSString’s stringWithString:(POSIX path of aFile)
  
set aData to current application’s NSData’s dataWithContentsOfFile:aFilePath options:0 |error|:(missing value)
  
set theStyledText to current application’s NSMutableAttributedString’s alloc()’s initWithData:aData options:(missing value) documentAttributes:(missing value) |error|:(missing value)
  
  
if theStyledText is not equal to missing value then
    return (theStyledText’s |string|()) as string
  else
    return false –Not RTF file
  end if
end retTextFromRTF

★Click Here to Open This Script 

2016/11/08 macOS Sierraで実行できなくなった処理

macOS Sierra(10.12)になって、実行できなくなった、実行しても指定値を無視される処理が出てきました。

具体的にいうと、System Events.appでセキュリティをゆるく設定するための処理を受け付けなくなりました。

sys_event_dict.jpg

スリープからの復帰(wake)時にパスワードを要求しない、という設定を行っても無視されるようになりました。

AppleScript名:Sierraで実行できなくなった処理1
–http://piyocast.com/as/archives/4308
–macOS Sierraで実行できなくなった命令
tell application “System Events”
  tell security preferences
    set require password to wake to false
    
set aRes to (require password to wake)
    
–> true
  end tell
end tell

★Click Here to Open This Script 

システム環境設定の「セキュリティとプライバシー」で、設定内容を変更するさいにパスワードを要求するかどうかの設定で、true(要求する)と指定してもfalse(要求しない)という結果が返ってきます。かならずパスワードは要求させる、という意図はわかるのですが、こちらは返ってきている値が間違っています(かならずtrueでないとおかしい)。

AppleScript名:Sierraで実行できなくなった処理2
–http://piyocast.com/as/archives/4308
–macOS Sierraで実行できなくなった命令
tell application “System Events”
  tell security preferences
    set require password to unlock to true
    
set aRes to (require password to unlock)
    
–> false
  end tell
end tell

★Click Here to Open This Script 

2016/05/31 デスクトップピクチャを白いピクチャとトグルで差し替え

ソフトウェアの説明書などを作る際に、ウィンドウやメニューなどの画面のスクリーンショットを撮ることが多々あります。そのような場合に、一時的にデスクトップピクチャを白い色にしておきたいことがあります。通常デスクトップピクチャと白いピクチャの切り替えを行うAppleScriptです。

普通にスクリプトエディタで本スクリプトをオープンしておいて、実行するたびにトグルで状態が切り替わります。

img_3596_resized.png
▲通常のデスクトップピクチャの表示状態

img_3597_resized.png
▲スクリーンショットを撮るために背景を白い画像に設定した状態

AppleScript名:デスクトップピクチャを白いピクチャとトグルで差し替え
– Created 2016-05-31 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

property aSwitch : false
property desktopPictures : {}
property aColpath : “”

if aSwitch = false then
  –デスクトップを白くする
  
set desktopPictures to getDesktopPicturePathList() of me
  
–白い画像を作成してデスクトップピクチャに設定
  
set aColpath to makeColordImageToTmp(255, 255, 255, 255) of me –R,G,B,A(それぞれ 0〜255)
  
setDesktopPicture(aColpath) of me
  
set aSwitch to true
else
  –保存しておいたDesktop Pictureのリストを戻す
  
setDesktopPicturePathList(desktopPictures) of me
  
do shell script “rm -f “ & quoted form of aColpath
  
set aSwitch to false
end if

–デスクトップピクチャの状態を復帰する
on setDesktopPicturePathList(aliasList)
  if aliasList = {} then
    display notification “保存しておいたデスクトップピクチャのリストが空になっています”
    
return
  end if
  
  
tell application “System Events”
    set dCount to count every desktop
    
repeat with i from 1 to dCount
      set j to contents of item i of aliasList
      
tell desktop i
        set picture to (POSIX path of j)
      end tell
    end repeat
  end tell
end setDesktopPicturePathList

–デスクトップピクチャの強制指定
on setDesktopPicture(aPathStr)
  tell application “System Events”
    set picture of every desktop to aPathStr
  end tell
end setDesktopPicture

–デスクトップピクチャのパスをaliasリストで取得
on getDesktopPicturePathList()
  set pList to {}
  
tell application “System Events”
    set dCount to count every desktop
    
repeat with i from 1 to dCount
      tell desktop i
        set aPic to (picture as POSIX file) as alias
        
set end of pList to aPic
      end tell
    end repeat
  end tell
  
return pList
end getDesktopPicturePathList

–テンポラリフォルダに指定色の画像を作成
on makeColordImageToTmp(rDat as integer, gDat as integer, bDat as integer, aDat as integer)
  set rCol to 255 / rDat
  
set gCol to 255 / gDat
  
set bCol to 255 / bDat
  
set aCol to 255 / aDat
  

  
set aColor to current application’s NSColor’s colorWithDeviceRed:rCol green:gCol blue:bCol alpha:aCol
  
set aDesktopPath to current application’s NSString’s stringWithString:(POSIX path of (path to temporary items))
  
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)
  
set aRes to makeImageWithFilledWithColor(1, 1, savePath, aColor) of me
  
return (savePath as string)
end makeColordImageToTmp

–指定サイズの画像を作成し、指定色で塗ってファイル書き出し
on makeImageWithFilledWithColor(aWidth, aHeight, outPath, fillColor)
  –Imageの作成  
  
set anImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight))
  
  
–描画実行
  
anImage’s lockFocus()
  
set theRect to {{x:0, y:0}, {height:aHeight, width:aWidth}}
  
set theNSBezierPath to current application’s NSBezierPath’s bezierPath
  
theNSBezierPath’s appendBezierPathWithRect:theRect
  
fillColor’s |set|()
  
theNSBezierPath’s fill()
  
anImage’s unlockFocus() –描画ここまで
  
  
–生成した画像のRaw画像を作成
  
set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
  
–書き出しファイルパス情報を作成
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
  
end makeImageWithFilledWithColor

★Click Here to Open This Script 

2016/05/30 Pure ASでチルダ入りパス文字列展開

チルダ入りのPOSIX path文字列(例:~/Library)をフルパス(/Users/me/Library)に展開する処理を行うAppleScriptです。

チルダの展開については、Cocoaの機能を用いるルーチンばかり使っていましたが、Pure AppleScript(Cocoaの機能を利用しないものをあえてこう呼ぶ)でも実行できるものを見つけて(ひとりで)腰を抜かしていました。

yyyeyoyycyaye-2016-05-30-183747_resized.png

一応1,000回繰り返し実行してスピードを計測してみたところ、ASOC版のほうが18倍ぐらい速いようです。ただ、そうむやみに実行するような内容でもないため、この程度なら速度よりも「思い出しやすさ」あたりがキーになりそうです。

AppleScript名:ASOCでチルダ入りパス展開
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set bPath to “~/Desktop”
set pathString to current application’s NSString’s stringWithString:bPath
set newPath to pathString’s stringByExpandingTildeInPath() as string
–>  (NSString) “/Users/me/Desktop”

★Click Here to Open This Script 

AppleScript名:Pure ASでチルダ入りパス展開
– Created 2016-05-13 by Christopher Stone

set aPath to “~/Desktop”
set aRes to expandTildeInPath(aPath) of me
–>  ”/Users/me/Desktop”

on expandTildeInPath(thePath)
  tell application “System Events”
    return (POSIX path of (disk item thePath))
  end tell
end expandTildeInPath

★Click Here to Open This Script 

2016/04/03 System Eventsのシステム環境設定系情報へのアクセス

System Eventsのシステム環境設定系情報へのAppleScriptからのアクセスを確認してみました。

歴史的に説明すると、システム環境設定の情報取得/設定のための機能は当初は「システム環境設定.app」(System Preferences.app)に実装されかけ、途中でSystem Eventsに引っ越してきました。今では、システム環境設定側には、各Preferences Paneの表示切り替えぐらいの機能しかAppleScript関連機能は残っていません。

System Eventsも建増し工事が続けられ、中には何に使うのかさっぱりわからない「Scripting Definition Suite」なんてありますが(AppleScript Libraries内で使用? デバッグ用?)、値の取り方を確認してみました。

System Events内でもpropertiesで一気に複数のプロパティ値を取得できるもの(例:Desktop Suite)とできないものがあり、ここに挙げたのはpropertiesで一気に取得できないものの方です。

「secure virtual memory」は用語として定義されているものの、OS X 10.10/10.11の両方で同じようにエラーが出ます(すでに、システム環境設定に項目が存在していないため、実行できなくても問題はないのですが)。用語を残しておけばScriptのオープン時にエラーは出ないので大丈夫だろうということでしょうか。そこのあたり、もう少し明示的にRelease Notesなどに書いてほしいところです。

なお、下記プログラム中における返り値の内容は私のマシン上で実行した結果であり、値は環境ごとに異なります。

AppleScript名:dock preferencesへのアクセス
– Created 2016-04-03 by Takaaki Naganoya
– 2016 Piyomaru Software
tell application “System Events”
  tell dock preferences
    set s1 to (animate)
    
–> true
    
    
set s2 to (autohide)
    
–> false
    
    
set s3 to (dock size)
    
–> 0.008928571828
    
    
set s4 to (magnification)
    
–> true
    
    
set s5 to (magnification size)
    
–> 1.0
    
    
set s6 to (minimize effect)
    
–> scale
    
    
set s7 to (screen edge)
    
–> right
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:security preferencesへのアクセス
– Created 2016-04-03 by Takaaki Naganoya
– 2016 Piyomaru Software
tell application “System Events”
  tell security preferences
    set s1 to (automatic login)
    
–> true
    
    
set s2 to (log out when inactive)
    
–> false
    
    
set s3 to (log out when inactive interval)
    
–> 60
    
    
set s3 to (require password to unlock)
    
–> false
    
    
set s3 to (require password to wake)
    
–> true
    
    
–secure virtual memory
    
–> error “System Events でエラーが起きました:AppleEvent のハンドラで誤りが起きました。” number -10000
  end tell
end tell

★Click Here to Open This Script 

AppleScript名:appearance preferencesへのアクセス
– Created 2016-04-03 by Takaaki Naganoya
– 2016 Piyomaru Software
tell application “System Events”
  tell appearance preferences
    set s1 to (appearance)
    
–> blue
    
    
set s2 to (font smoothing)
    
–> true
    
    
set s3 to (font smoothing style)
    
–> automatic
    
    
set s4 to (highlight color)
    
–> {42075, 52602, 65482}
    
    
set s5 to (recent applications limit)
    
–> 50
    
    
set s6 to (recent documents limit)
    
–> 50
    
    
set s7 to (recent servers limit)
    
–> 10
    
    
set s8 to (scroll bar action)
    
–> jump to next page
    
    
set s9 to (smooth scrolling)
    
–> true
    
    
set s10 to (dark mode)
    
–> false
    
  end tell
end tell

★Click Here to Open This Script 

2016/04/03 dark modeへの切り替えを高速で繰り返す

Dark Modeへの切り替えがSystem Eventsに実装されていることに気づかず、調べて驚きました。

ものすごく簡単に状態の取得と切り替えが行えるわけで、これだけならわざわざCocoaの機能を呼び出さなくても大丈夫でしょう。System Eventsに実装されているシステム情報の取得/設定系の機能はOSのアップデートのたびにバグが出やすい場所なので(なんで正式OSリリースまでに直さないかな)、複数のやりかたを用意しておくのが賢明です。

0.1秒のディレイでDark ModeとLight Modeを切り替えてみました。何か、通知を行うようなときに便利かもしれません。

AppleScript名:dark modeへの切り替えを高速で行う
– Created 2016-04-03 by Takaaki Naganoya
– 2016 Piyomaru Software
tell application “System Events”
  tell appearance preferences
    repeat 10 times
      set (dark mode) to false
      
delay 0.1
      
set (dark mode) to true
      
delay 0.1
    end repeat
    
set (dark mode) to false
  end tell
end tell

★Click Here to Open This Script 

2015/08/09 使用中のMacの製品呼称を取得する

使用中のMacの製品呼称を取得するAppleScriptです。

本来は、Cocoaの機能を呼び出してXMLをparseしようとしてこの数倍のプログラムを組んでいたのですが、いまひとつうまくいかずに挫折。System Eventsでparseするという安直な方法に落ち着きました(^ー^;;

→ ここの情報を参照しました

製品呼称コードは4文字パターン(例:DKQ2)と3文字パターン(例:5RU)があるようなので、シリアル番号から両方の文字列を作成して、両方試すと確実ではないでしょうか。

MacBook Air 2014で実行すると、「MacBook Air」としか返してこないことを確認、、、、いろいろ例外がありそうです。

AppleScript名:使用中のMacの製品呼称を取得する
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aSerial to retSerial()
set aID to text ((length of aSerial) - 3) thru -1 of aSerial

set aRes to do shell script “curl -o - http://support-sp.apple.com/sp/product?cc=” & aID & “&lang=en_US”
–> “<?xml version=\”1.0\” encoding=\”utf-8\” ?><root><name>CPU Name</name><configCode>MacBook Pro (Retina, Mid 2012)</configCode><locale>en_US</locale></root>”

tell application “System Events”
  set aData to make new XML data with properties {text:aRes}
  
set aModel to value of XML element “configCode” of XML element “root” of aData
end tell
–> “MacBook Pro (Retina, Mid 2012)”

–Get Your Mac’s Hardware Serial Code
on retSerial()
  set a to (do shell script “system_profiler SPHardwareDataType | grep Serial”)
  
set b to offset of “:” in a
  
set c to (characters (b + 2) thru -1 of a) as text
  
return c
end retSerial

★Click Here to Open This Script 

2015/08/06 フォルダアクションの操作

OS X 10.10では当初いろいろトラブルがありましたが、Folder Actionは依然として「使える」機能であることにはかわりはありません。

ただし、いくつかの仕組みが絶対的に「足りていない」ことは日々感じています。

それは、Webブラウザのダウンロード開始/終了/中断にともないScriptの実行を呼び出すような仕組み です。

とりあえず、ないものを嘆いても仕方がないので、そうした機能を実現するため、

「メインScriptとFolder Action Scriptの間でハンドシェイクを行い、Web系の非同期ダウンロードの完了を検知してダウンロードしたファイルへの処理を実施」

といった処理を行っています。

たしかに、(Finderさえコケなければ ←重要!!!)この処理は万全ではあるのですが、いささか処理が込み入りすぎているため、トラブル発生時の対応や機能の追加が行いにくい状態になっています。また、ユーザーが誤ってSafariのDownloadフォルダにGUI経由でファイルを移動させたりできてしまうため、そうした操作を除外できない(ユーザーが手を触れないことが処理の前提)ところも問題です。

かといって、AppleがSafariに対してScript系の機能を大々的に追加することも考えにくいところ。根本的な問題の解決は、

「すべてAppleScriptObjCで記述したWebブラウザを作ること」

だけです。WebViewの表示やキーチェーンまわりはWebKitに任せてしまえるため、各種イベントやNotificationを受信するように機能を整えてあげればよいのですが・・・なかなか、そのコストを誰がどーやって負担するのかが不明瞭。

AppleScript名:フォルダアクションのオン、オフ
tell application “System Events”
  set fRes to folder actions enabled
  
set folder actions enabled to true
  
set f2Res to folder actions enabled
end tell

★Click Here to Open This Script 

AppleScript名:設定されているフォルダアクションをすべて取得する
tell application “System Events”
  –すべてのフォルダアクションを取得
  
set fList to every folder action
  
  
–フォルダアクションでループ
  
repeat with i in fList
    
    
–フォルダアクションのプロパティ
    
set j to contents of i
    
properties of j
    
–> {path:alias “Macinotsh HD:Users:me:Downloads:”, volume:”Cherry”, enabled:true, name:”Downloads”, has new changes:false, class:folder action}
    
    
    
–フォルダアクションのScript    
    
set sRes to script of j
    
–> {script “add - new item alert.scpt” of folder action “Downloads” of application “System Events”}
    
    
–Scriptのプロパティ
    
set aScript to first item of sRes
    
properties of aScript
    
–> {enabled:true, path:”Macintosh HD:Library:Scripts:Folder Action Scripts:add - new item alert.scpt”, POSIX path:”/Library/Scripts/Folder Action Scripts/add - new item alert.scpt”, class:script, name:”add - new item alert.scpt”}
    
  end repeat
  
end tell

★Click Here to Open This Script 

2015/07/29 指定名称のアプリをフルスクリーン表示

指定名称のアプリケーションをフルスクリーン表示するAppleScriptです。フルスクリーン表示させるアプリケーションはあらかじめ起動しておく必要があります。

また、GUI Scriptingを用いているため、実行前にあらかじめ「システム環境設定」>「セキュリティとプライバシー」>「アクセシビリティ」で本Scriptを実行するアプリケーション(おそらく、スクリプトエディタ)にコンピュータの(GUI側からの)制御を許可するよう設定しておく必要があります。

この手のScriptはよく見かけるのですが、自分の環境でしか動かないものを公開している例が多く、少し汎用性と柔軟性をもたせてみました。ただし、フルスクリーン表示の解除はサポートしていません(終了させればよいのでは? ^ー^;)。

フルスクリーン表示はOS X 10.7で搭載されましたが、これをAppleScriptからコントロールするまっとうな手段は用意されてきませんでした。次善の策として(やりたくないけど、仕方なく)GUI Scriptingでコントロールすることになります。

アプローチ方法は主に3つ。

(1)メニューを操作してフルスクリーン化
(2)キーボードショートカットを実行してフルスクリーン化

本Scriptでは、

(3)ウィンドウのフルスクリーン/ズームボタンをクリック

を採用しています。

本Scriptで柔軟性を持たせたのは3点。

(1)アプリケーション名称に、本当の名前(name)でもローカライズされた名称(displayed name)でもどちらでも許容する

(2)フルスクリーン表示がサポートされていないアプリケーションでは、ウィンドウの最大化を行う

(3)メニューの表示項目名などを使っていないため、使用/実行言語環境に左右されない

といったところです。

buttons.png

本来は、アプリケーションのプロパティなり、

–> {frontmost:false, class:application, name:”Safari”, version:”9.0″, full screen:true}

ウィンドウのプロパティにフルスクリーン表示状態を示すものが存在して、

–> {document:document “AS Hole(AppleScriptの穴) By Piyomaru Software”, closeable:true, zoomed:true, class:window, index:1, visible:true, name:”AS Hole(AppleScriptの穴) By Piyomaru Software”, modal:false, miniaturizable:true, titled:true, id:88, miniaturized:false, floating:false, resizable:true, bounds:{26, 23, 901, 1195}, current tab:tab 1 of window id 88, zoomable:true, full screen:true}

その操作によりフルスクリーン/ズーム表示を変更できることが望ましいところです。ただし、最近のUS AppleのAppleScriptエンジニアリングチームは、ASOCでCocoaの機能を使ってScripter側に勝手にやらせようということが多く、Finderの「タグ」にしてもフルスクリーン表示にしても、OS側の新機能にキャッチアップしていない部分が多くて困ります。

printコマンドで出力プリンタ名称を指定できても、肝心のプリンタ名称を取得する手軽でまっとうな方法が標準命令に存在していない点などは、どうかしています。結局、Apple側の対応を待たずにいろいろScripter側でやっているわけで…

AppleScript名:指定名称のアプリをフルスクリーン表示
– Created 2015-07-29 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions

set a to “Safari”
set aRes to dispAppWithFullScreen(a) of me

–指定名称のアプリケーション(起動中のもの)をフルスクリーン表示
on dispAppWithFullScreen(applicationName)
  
  
set appName to returnExactNameOfAnApp(applicationName)
  
if appName = false then return false –指定のアプリがなかった、あるいはアプリケーション名を間違って指定した
  
  
set pID to id of application appName
  
  
tell application appName
    reopen
    
activate
  end tell
  
  
tell application “System Events”
    tell (process 1 whose bundle identifier is pID)
      set b1List to every button of window 1 whose subrole is “AXFullScreenButton” –Full Screen
      
set b2List to every button of window 1 whose subrole is “AXZoomButton” –Zoom
      
      
if b1List = {} then
        set targB to first item of b2List –フルスクリーン表示機能を持たないアプリの場合
      else
        set targB to first item of b1List –フルスクリーン表示機能を持つアプリの場合
      end if
      
      
click targB
    end tell
  end tell
  
  
return true
  
end dispAppWithFullScreen

–Displayed Nameでアプリケーション名が与えられた場合に、正しい名称を返す
on returnExactNameOfAnApp(aName)
  tell application “System Events”
    set ap1List to every process whose name is equal to aName
    
if ap1List = {} then
      set ap1List to every process whose displayed name is equal to aName
      
if ap1List = {} then return false
    end if
    
set anApp to contents of first item of ap1List
    
return name of anApp
  end tell
end returnExactNameOfAnApp

★Click Here to Open This Script 

2015/05/30 Radikoで選局v6

SafariでRadiko.jpをオープンして現在の地域で選局可能なラジオ局の一覧を取得し、一覧から選択したあとに、指定したラジオ局をオープンするAppleScriptです。

自作のAppleScriptObjCのアプリケーション「radiRec」(あくまで個人用)に組み込んで、指定時刻に指定ラジオ局の番組を録音するために作成したものです。

Safariアプリケーション内のWebViewへの参照がいろいろ変わるので、そうした動的な変動を吸収するための機構を追加しました。

GUI Scripting経由でSafariにアクセスしているので、システム環境設定からあらかじめ「アクセシビリティ」から「補助装置にアクセスできるようにする」にチェックを入れておくか、Script実行時にパスワードを入力すると設定を変更します。

radiko41.png

OS X 10.10.3+Safari 8.0.7、場所は東京都内で動作確認してあります(他のエリアではチェックしていません)。

AppleScript名:Radikoで選局v6
–WevViewへの参照を動的に取得するように変更
–OS X 10.10.3(本当は4だけど), Safari 8.0.7, Radiko.jpがプレミアム会員サービスを開始した状態に対応

property waitSec : 10 –Safariのページローディングを待つ時間(秒)

–GUI Scriptingの確認
repeat 3 times
  tell application “System Events”
    set aRes to UI elements enabled
  end tell
  
  
if aRes = false then
    display dialog “GUI Scriptingをオンにしてください。” buttons {“OK”} default button 1
    
tell application “System Events”
      activate
      
set UI elements enabled to true
    end tell
  end if
end repeat
if aRes = false then return

set aList to getRadioStationList() of me
–> {”TBSラジオ”, “文化放送”, “ニッポン放送”, “ラジオNIKKEI第1″, “ラジオNIKKEI第2″, “InterFM”, “TOKYO FM”, “J-WAVE”, “ラジオ日本”, “bayfm78″, “NACK5″, “FMヨコハマ”, “放送大学”}

tell current application
  activate
  
set aRes to choose from list aList
end tell

set aaRes to first item of aRes

selectRadioStation(aaRes) of me –選曲

–SafariでRadikoの選局を行う
on selectRadioStation(aStation)
  activate application “Safari”
  
  
tell application “Safari”
    close every document
    
    
tell document 1
      tell current tab
        open location “http://radiko.jp”
      end tell
    end tell
  end tell
  
  
delay waitSec
  
  
tell application “System Events”
    tell process “Safari”
      
      
set webView to retSafariHTMLViewReference() of me
      
tell webView
        tell list 2
          –ログイン/プレミアム会員登録の箇所が増えたのでlist2に
          
set gList to every group
          
          
set uList to {}
          
          
repeat with i in gList
            tell i
              tell group 1 –ここ、1階層増えた
                set a to UI element 1
                
set statName to title of a
                
set the end of uList to statName
                
if statName = aStation then
                  
                  
click a
                  
                end if
              end tell
            end tell
          end repeat
          
        end tell
        
      end tell
    end tell
  end tell
  
end selectRadioStation

–SafariでRadikoのラジオ局一覧を取得する
on getRadioStationList()
  activate application “Safari”
  
  
tell application “Safari”
    close every document
    
    
tell document 1
      tell current tab
        open location “http://radiko.jp”
      end tell
    end tell
  end tell
  
  
delay waitSec
  
  
tell application “System Events”
    tell process “Safari”
      set webView to retSafariHTMLViewReference() of me
      
tell webView
        
        
tell list 2
          –ログイン/プレミアム会員登録の箇所が増えたのでlist2に
          
set gList to every group
          
          
set uList to {}
          
          
repeat with i in gList
            tell i
              tell group 1 –ここ、1階層増えた
                set a to UI element 1
                
set statName to title of a
                
set the end of uList to statName
              end tell
            end tell
          end repeat
          
          
return uList
          
        end tell
      end tell
      
    end tell
  end tell
  
end getRadioStationList

–SafariのWebViewへのGUI Scripting的な参照を取得する
on retSafariHTMLViewReference()
  tell application “System Events”
    tell process “Safari”
      
      
set wList to every window
      
set wLen to length of wList
      
if wLen = 0 then return false
      
      
tell window 1
        repeat with i from 1 to 10 –Usually from 1 to 5
          try
            tell group i
              tell UI element 1 of scroll area 1 of group 1 of group 1
                set aProp to role
                
if aProp = “AXWebArea” then
                  return (UI element 1 of scroll area 1 of group 1 of group 1 of group i of window 1 of process “Safari” of application “System Events”)
                end if
              end tell
            end tell
          end try
          
        end repeat
      end tell
      
    end tell
  end tell
end retSafariHTMLViewReference

★Click Here to Open This Script 

2014/12/12 バージョン番号文字列からメジャーバージョンを求める v2v3

バージョン番号文字列(”10.10.1”とか”4.1.1”とか)から、メジャーバージョン番号の数値(10とか4とか)を求めるAppleScriptです。

最初のバージョンでは、アプリケーション名称(display name)と本当の名称(プロセス名)が異なるものについては、AppleScript側から「これはなんですか?」といちいち聞かれていたので、nameではなくBundle IDを取得してバージョン番号を求めるようにしてみました(Safariだけ確認したかったので、最初のバージョンは手抜き感が、、、visible processのみ処理していたのは、手抜きゆえに ^ー^;;)。

しかも、本ルーチン・・・作っていたシステムで「バージョンを確認しなくてもいい処理方法」を見つけたので、おクラ入りしたモノだったり。いつか、使うことになる日もくるでしょう、きっと。

AppleScript名:バージョン番号文字列からメジャーバージョンを求める v2
tell application “System Events”
  set bList to bundle identifier of every process whose visible is true
  
set nList to name of every process whose visible is true
end tell

set nnList to somelistAdd({nList, bList}) of me

set vList to {}
repeat with i in nnList
  set {aName, aBundleID} to contents of i
  
tell application id aBundleID
    set aVerStr to version
  end tell
  
set the end of vList to {aName, getMajorVersionNum(aVerStr) of me}
end repeat

return vList
–> {{”Finder”, 10}, {”Activity Monitor”, 10}, {”DragThing”, 5}, {”Keynote”, 6}, {”Safari”, 8}, {”Calendar”, 8}, {”Mail”, 8}, {”ASObjC Explorer 4″, 4}, {”iTunes”, 12}, {”Script Editor”, 2}, {”UI Browser”, 2}, {”Skim”, 1}}

–バージョンNo文字列のメジャー番号を取得する
on getMajorVersionNum(vString)
  set aPos to offset of “.” in vString
  
if aPos = 0 then
    set vStr to vString
  else
    set vStr to text 1 thru (aPos - 1) of vString
  end if
  
  
try
    set vNum to vStr as number
  on error
    return false
  end try
  
  
return vNum
end getMajorVersionNum

–複数のリストを合成
–すべて同じ要素数である必要がある。また、複数のリストを{aList,bList,cList}とペアにして
–本ルーチンに渡す必要がある
on somelistAdd(aList)
  set aCount to count every item of aList
  
–> 3
  
  
–渡された入れ子リスト内の各要素の数が同じかどうかチェック
  
set countList to {}
  
repeat with i from 1 to aCount
    set bCount to count every item of item i of aList
    
set the end of countList to bCount
  end repeat
  
–> {3, 3, 3}
  
set {aResF, aResN} to retSameEveryItem(countList) of me
  
if aResF = false then return –合成する要素内の要素数が合っていなかったら処理を行わない
  
  
–合成を行う
  
set newList to {}
  
repeat with i from 1 to aResN
    set anItem to {}
    
repeat with ii from 1 to aCount
      set jj to contents of (item i of item ii of aList)
      
set the end of anItem to jj
    end repeat
    
set the end of newList to anItem
  end repeat
  
  
return newList
end somelistAdd

–リスト中の全要素が同じかどうかをbooleanで返す
on retSameEveryItem(aList)
  set a to item 1 of aList
  
set aList to rest of aList
  
set aFlag to true
  
repeat with i in aList
    if a is not equal to contents of i then
      set aFlag to false
      
exit repeat
    end if
  end repeat
  
return {aFlag, a} –Booleanとそのデータを返す
end retSameEveryItem

★Click Here to Open This Script 

で、Shaneからツッコミがあって「こっちのほうがいいよ」と送ってもらったのがこちらです(^ー^;

AppleScript名:バージョン番号文字列からメジャーバージョンを求める v3
– Created 2014-12-12 by Shane Stanley
– 2014 Shane Stanley
use AppleScript version “2.3.1″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set theProcesses to current application’s NSWorkspace’s sharedWorkspace()’s runningApplications() as list
set theResult to {}

repeat with aProcess in theProcesses
  set anNSURL to aProcess’s bundleURL()
  
  
if anNSURL is not missing value then
    set theNSBundle to (current application’s NSBundle’s bundleWithURL:anNSURL)
    
    
if theNSBundle is not missing value then
      set theVersionString to ((theNSBundle’s infoDictionary())’s objectForKey:“CFBundleShortVersionString”)
      
      
if theVersionString is not missing value then
        set end of theResult to {aProcess’s localizedName() as text, (theVersionString’s componentsSeparatedByString:“.”)’s firstObject()’s integerValue()}
      end if
      
    end if
  end if
  
end repeat

return theResult

–> {{”loginwindow”, 9}, {”SystemUIServer”, 1}, {”Dock”, 1}, {”AirPlayUIAgent”, 2}, {”Finder”, 10}, {”Spotlight”, 1}, {”com.apple.internetaccounts”, 1}, {”CoreServicesUIAgent”, 134}, {”com.apple.dock.extra”, 1}, {”日本語入力プログラム”, 5}, {”アクティビティモニタ”, 10}, {”Folder Actions Dispatcher”, 1}, {”", 1}, {”QuickRes”, 4}, {”TISwitcher”, 1}, {”通知センター”, 1}, {”Keychain Circle Notification”, 1}, {”DragThing”, 5}, {”Colors for Hue”, 1}, {”EventScripts”, 1}, {”AAM Updates Notifier”, 8}, {”iCloud フォト”, 2}, {”AdobeIPCBroker”, 5}, {”universalAccessAuthWarn”, 1}, {”Wi-Fi”, 1}, {”System Events”, 1}, {”DragThing Helper”, 1}, {”Core Sync”, 1}, {”LaterAgent”, 1}, {”メール”, 8}, {”Mail Web コンテンツ”, 10600}, {”com.apple.MailServiceAgent”, 8}, {”AppleSpell.service”, 2}, {”Mail Web コンテンツ”, 10600}, {”Safari”, 8}, {”Safari Web コンテンツ”, 10600}, {”Safari Networking”, 10600}, {”スクリプトエディタ”, 2}, {”ASObjC Explorer 4″, 4}, {”ASObjCExplorerUIRunner”, 1}}

★Click Here to Open This Script 

2014/12/03 指定アプリケーションがフルスクリーン状態かどうか調べる

指定名称のアプリケーションがフルスクリーン表示状態かどうか調べるAppleScriptです。

冒頭のdelay文はAppleScriptを実行させたあとにSafariを(手動で)フルスクリーン表示させて動作確認させたときのものです。

AppleScript名:指定アプリケーションがフルスクリーン状態かどうか調べる
– Created 2011-07-25 Bill Cheeseman
use AppleScript version “2.4″
use scripting additions

delay 10

set aRes to chkFullScreen(“Safari”) of me
–> false –Not Full Screen
–> true –Full Screen

–指定アプリケーションがフルスクリーン表示になっているかを調べる
on chkFullScreen(appName)
  try
    tell application “System Events”
      tell process appName
        set fRes to get value of attribute “AXFullScreen” of window 1
      end tell
    end tell
  on error
    set fRes to false
  end try
  
  
return fRes
  
end chkFullScreen

★Click Here to Open This Script 

2014/04/15 現在のマシン上の全ユーザーアカウントを取得して、管理者権限を持っているものだけを返す

Scriptを実行中のマシン上の全ユーザーアカウントを取得して、そのうち管理者権限を持っているアカウントだけを抽出してリストで返すAppleScriptです。

さるアプリケーションの起動プロセスで、システムにあるファイルが存在していない場合にはインストールを行うようにすることになり……Objective-Cでやると大変なので、AppleScriptで行うことに。

# インストーラーを作成すれば、このあたりは自動でやってもらえるのですが
# インストーラーを作成するためにはCodeSignが必要で、お客様にその手間を
# かけていただくのは物理的に無理だったので、こんなイバラの道を……

do shell scriptには管理者パスワードを指定することで管理者権限で実行できる(with administrator privileges)ので、安直にdo shell scriptでやればよい……そんな風に考えていた時代もありました。しかし、現在ログイン中のユーザーが管理者権限を持っている場合にはそれでよいのですが、管理者権限を持っていないユーザーでログイン中だったらどうするのか?

do shell scriptを管理者権限で実行するためには、ユーザー名も指定しなければなりません。それは……調べてユーザーに提示しないと、分らないわけで………

仕方なく、いろいろ探しては組みはじめるわけですが……その結果、こんな感じになりました。いや、当初想定していたよりも大変なこと大変なこと。15分ぐらいかかってしまいました。

スクリプト名:現在のマシン上の全ユーザーアカウントを取得して、管理者権限を持っているものだけを返す
set adList to getAdminUserNames()
–> {”maro”, “piyo”}

–現在のマシン上の全ユーザーアカウントを取得して、管理者権限を持っているものだけを返す
on getAdminUserNames()
  –マシン上の全ユーザーアカウントのユーザー名を取得
  
tell application “System Events”
    set userNameList to name of every user
  end tell
  
  
–全ユーザー名のうち、管理者権限を持っているものだけを抽出
  
set adminNames to {}
  
repeat with i in userNameList
    set j to contents of i
    
set uRes to getUsersPrivileges(j)
    
if uRes = true then
      set the end of adminNames to j
    end if
  end repeat
  
  
return adminNames
end getAdminUserNames

–現在実行中のユーザーの権限を得る(管理者か、それ以外か) 10.4および10.5以降両用
–管理者だとtrueが、それ以外だとfalseが返る
on getUsersPrivileges(aUser)
  set aVer to system attribute “sys2″ –OSメジャーバージョンを取得する(例:Mac OS X 10.6.4→6)
  
  
if aVer > 4 then
    –Mac OS X 10.5以降の処理
    
set adR to (do shell script “/usr/bin/dsmemberutil checkmembership -U “ & aUser & ” -G admin users”)
    
    
if adR = “user is a member of the group” then
      return true
    else
      return false
    end if
    
  else
    –Mac OS X 10.4までの処理
    
set admin_users to (do shell script “/usr/bin/niutil -readprop . /groups/admin users”)
    
tell (a reference to AppleScript’s text item delimiters)
      set {old_atid, contents} to {contents, ” “}
      
set {admin_users, contents} to {text items of admin_users, old_atid}
    end tell
    
    
if aUser is in admin_users then
      return true
    else
      return false
    end if
  end if
  
end getUsersPrivileges

–現在実行中のユーザーの権限を得る(管理者か、それ以外か) 10.4および10.5以降両用
–管理者だとtrueが、それ以外だとfalseが返る
on getCurUsersPrivileges()
  set aVer to system attribute “sys2″ –OSメジャーバージョンを取得する(例:Mac OS X 10.6.4→6)
  
  
set current_user to (do shell script “whoami”) –実行中のユーザー名を取得
  
  
if aVer > 4 then
    –Mac OS X 10.5以降の処理
    
set adR to (do shell script “/usr/bin/dsmemberutil checkmembership -U “ & current_user & ” -G admin users”)
    
    
if adR = “user is a member of the group” then
      return true
    else
      return false
    end if
    
  else
    –Mac OS X 10.4までの処理
    
set admin_users to (do shell script “/usr/bin/niutil -readprop . /groups/admin users”)
    
tell (a reference to AppleScript’s text item delimiters)
      set {old_atid, contents} to {contents, ” “}
      
set {admin_users, contents} to {text items of admin_users, old_atid}
    end tell
    
    
if current_user is in admin_users then
      return true
    else
      return false
    end if
  end if
  
end getCurUsersPrivileges

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

2014/03/31 現在見えているWiFiネットワークの情報を返す

現在Macから見えているWiFi(無線LAN)ネットワークの情報を取得するAppleScriptです。

ssid1.png

airportコマンドでいろいろ情報を取得しているので、WiFiネットワーク名(SSID_STR)以外にもいろいろ取得できます。

記述してテストしたのはSSD搭載のMacBook Pro Retinaだったのですが、airportコマンドで情報をplistに書き込ませたあとにSystem Eventsで読み込む際、ディスクの書き込みが終わる前に次の処理に進んでしまって「ファイルがない」と言われるケースがあったので、少々しつこくsyncコマンドを実行しています。

あとは、WiFiネットワークが見えたり見えなかったりで、実行するたびに毎回結果が微妙に異なったりするのは「お約束」です。

気のせいか、airportコマンドで-xでXML出力指定すると、(オプションによっては)通常出力される場合とデータ項目数が微妙に異なっている場合があるように見えます。「-I -x」と指定したときに、単に「-I」とは項目が違っており、びみょーにバグの香りが、、、、

スクリプト名:現在見えているWiFiネットワークの情報を返す

set aRec to getVisibleWiFiNetInfo() of me

set nList to {}

repeat with i in aRec
  set j to contents of SSID_STR of item 2 of i
  
set the end of nList to j
end repeat

nList
–> {”0622XXXXXXXX-X”, “ExtrXXXXXXX_XX”, “Buffalo-X-XXXX”, “0024XXXXXXXX”, “auhome_XXXXXX”, “BCW7XXXXXXXXXXX”, “0024XXXXXXXX-X”, “4CE6XXXXXXXX-X”, “BCW7XXX-XXXXX-X”, “4CE6XXXXXXXX”}

–現在見えているWiFiネットワークの情報を返す
on getVisibleWiFiNetInfo()
  
  
–一時ファイルのパス生成
  
set tPath to retTempPosixPath(“.plist”) of me
  
  
do shell script (“/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s -x > “ & tPath)
  
  
do shell script “sync” –たまにディスク書き込みが間に合わないケースがあったので、強制実行
  
do shell script “sync” –たまにディスク書き込みが間に合わないケースがあったので、強制実行
  
do shell script “sync” –たまにディスク書き込みが間に合わないケースがあったので、強制実行
  
  
set wifiRes to {}
  
  
tell application “System Events”
    set plif to property list file tPath
    
set pitm to every property list item of plif
    
repeat with p in pitm
      set end of wifiRes to {name, value} of p
    end repeat
  end tell
  
  
–一時ファイルの削除
  
do shell script “rm -f “ & tPath
  
  
return wifiRes
  
end getVisibleWiFiNetInfo

–テンポラリフォルダ内のテンポラリファイルを返す
on retTempPosixPath(aExt)
  set tPath to path to temporary items from user domain
  
set tpPath to POSIX path of tPath
  
set aFile to (do shell script “uuidgen”) & aExt
  
set tFile to tpPath & aFile
  
return tFile
end retTempPosixPath

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

2013/11/28 Dockの表示/非表示制御

Dockを表示させたり、隠したりするAppleScriptです。

たまたま、全画面を半透明ウィンドウで覆って処理を行うプログラムをAppleScriptObjCで組んでいて、Dockが表示されていて邪魔でした。ここで可能な選択肢は、

(1)Dockよりも上にウィンドウを表示する
(2)ウィンドウ表示する前にDockを隠す

のうちのどちらか。

(1)は別に難しくはないものの、この間「自分のウィンドウをOSの最前面に配置してdisplay dialogを実行」して、自分のウィンドウよりも「下」にダイアログが表示されてクリックできずに再起動 という悲しい目にあったので、却下

(2)は割といい方法ですが、Dockの制御はあまりやらない処理なので、Scriptのストックがありませんでした。

というわけで、Dockの表示/非表示(隠す)のやりかたをまとめておきました。OS X 10.5以降であれば動くはずです。動作確認をOS X 10.6〜10.9で行いました。

なお、OS X 10.6上でログイン直後にSystem Eventsを呼ぶ(起動項目にAppleScriptアプレットを登録するなど)と、System Eventsの起動が終わり切っておらずエラーになる可能性があるので注意が必要です。

スクリプト名:Dockを隠す
tell application “System Events”
  set autohide of dock preferences to true
end tell

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

スクリプト名:Dockを表示する
tell application “System Events”
  set autohide of dock preferences to false
end tell

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

2013/08/27 アプリケーションフォルダ以下のアプリケーションのローカライズ数をカウントする

バンドルパッケージ内のフォルダ/ファイルを普通にAppleScriptのaliasで扱えることを確認するための実験です。

アプリケーションフォルダへのパスを求め、その下にある「アプリケーション」をspotlightですべてリストアップ。求めたアプリケーションの中の「Contents:Resources:」フォルダ内にある「なんちゃら.lproj」フォルダの数を数えて、さらにそれらのフォルダ名の一覧を作成。フォルダ数の多いものから降順ソートを行っています。

Mac OS X自体のローカライズ言語数が30(OS X 10.8.4上にて)なのに、なぜかローカライズ言語数が92もあるVLCとか、53もあるGoogle Chromeは何をやっているのか興味があるところです(そもそも、判別できるのやら)。

ちなみに、このScriptを作ること自体が目的ではなく、最終的に作りたい「別のモノ」の練習のために作ったものなので「mdlsコマンドでローカライズ言語数が分るよ」とかいう指摘はしないでください。

スクリプト名:アプリケーションフォルダ以下のアプリケーションのローカライズ数をカウントする
set outList to {}

set startDir to path to applications folder
set bList to getFileListWithSpotLight(“kMDItemKind”, “アプリケーション”, startDir) of me –日本語環境下でのみ有効

repeat with i in bList
  tell application “Finder”
    set appName to name of i
  end tell
  
  
set appPath to i as string
  
set resPath to appPath & “Contents:Resources:”
  
tell application “Finder”
    tell folder resPath
      try
        set fList to (every folder whose name ends with “.lproj”) as alias list
        
set fnList to (name of every folder whose name ends with “.lproj”) as alias list
        
set fn2List to shellSortAscending(fnList) of me
        
        
set the end of outList to {appName, length of fList, fn2List}
      on error
        set the end of outList to {appName, 1, {“English.lproj”}}
      end try
    end tell
  end tell
  
end repeat

set cList to shellSortListDescending(outList, 2) of me

–> {{”VLC.app”, 92, {”ach.lproj”, “af.lproj”, “am.lproj”, “an.lproj”, “ar.lproj”, “ast.lproj”, “az.lproj”, “be.lproj”, “bg.lproj”, “bn_IN.lproj”, “bn.lproj”, “br.lproj”, “ca.lproj”, “cgg.lproj”, “ckb.lproj”, “co.lproj”, “cs.lproj”, “cy.lproj”, “da.lproj”, “de.lproj”, “el.lproj”, “en_GB.lproj”, “English.lproj”, “es.lproj”, “et.lproj”, “eu.lproj”, “fa.lproj”, “ff.lproj”, “fi.lproj”, “fr.lproj”, “fur.lproj”, “ga.lproj”, “gd.lproj”, “gl.lproj”, “gu.lproj”, “he.lproj”, “hi.lproj”, “hr.lproj”, “hu.lproj”, “hy.lproj”, “ia.lproj”, “id.lproj”, “is.lproj”, “it.lproj”, “ja.lproj”, “ka.lproj”, “kk.lproj”, “km.lproj”, “kmr.lproj”, “ko.lproj”, “ky.lproj”, “lg.lproj”, “lt.lproj”, “lv.lproj”, “mk.lproj”, “ml.lproj”, “mn.lproj”, “mr.lproj”, “ms.lproj”, “my.lproj”, “nb.lproj”, “ne.lproj”, “nl.lproj”, “nn.lproj”, “oc.lproj”, “or_IN.lproj”, “pa.lproj”, “pl.lproj”, “ps.lproj”, “pt_BR.lproj”, “pt_PT.lproj”, “ro.lproj”, “ru.lproj”, “si.lproj”, “sk.lproj”, “sl.lproj”, “sq.lproj”, “sr.lproj”, “sv.lproj”, “ta.lproj”, “te.lproj”, “tet.lproj”, “th.lproj”, “tl.lproj”, “tr.lproj”, “uk.lproj”, “uz.lproj”, “vi.lproj”, “wa.lproj”, “zh_CN.lproj”, “zh_TW.lproj”, “zu.lproj”}}, {”Adobe Application Manager.app”, 61, {”ar_AE.lproj”, “ar.lproj”, “cs_CZ.lproj”, “cs.lproj”, “da_DK.lproj”, “da.lproj”, “de_DE.lproj”, “de.lproj”, “el_GR.lproj”, “el.lproj”, “en_GB.lproj”, “en_US.lproj”, “English.lproj”, “es_419.lproj”, “es_ES.lproj”, “es_LA.lproj”, “es_MX.lproj”, “es_NA.lproj”, “es.lproj”, “fi_FI.lproj”, “fi_FL.lproj”, “fi.lproj”, “fr_CA.lproj”, “fr_FR.lproj”, “fr_XM.lproj”, “fr.lproj”, “he_IL.lproj”, “he.lproj”, “hu_HU.lproj”, “hu.lproj”, “it_IT.lproj”, “it.lproj”, “ja_JP.lproj”, “ja.lproj”, “ko_KR.lproj”, “ko.lproj”, “nb_NO.lproj”, “nb.lproj”, “nl_NL.lproj”, “nl.lproj”, “no_NB.lproj”, “no.lproj”, “pl_PL.lproj”, “pl.lproj”, “pt_BR.lproj”, “pt.lproj”, “ro_RO.lproj”, “ro.lproj”, “ru_RU.lproj”, “ru.lproj”, “sv_SE.lproj”, “sv.lproj”, “tr_TR.lproj”, “tr.lproj”, “uk_UA.lproj”, “uk.lproj”, “zh_CN.lproj”, “zh_TW.lproj”, “zh-Hans.lproj”, “zh-Hant.lproj”, “zh.lproj”}},……

–指定階層下で、指定クリエータコードのファイルを取得(Mac OS X 10.4.x以上で動作)
on getFileListWithSpotLight(aMetaDataItem, aParam, startDir)
  
  
set sDirText to quoted form of POSIX path of startDir
  
set shellText to “mdfind ‘” & aMetaDataItem & ” == \”" & aParam & “\”‘ -onlyin “ & sDirText
  
try
    set aRes to do shell script shellText
  on error
    return {}
  end try
  
set pList to paragraphs of aRes
  
set aList to {}
  
repeat with i in pList
    set aPath to POSIX file i
    
set aPath to aPath as alias
    
set the end of aList to aPath
  end repeat
  
return aList
end getFileListWithSpotLight

–シェルソートで入れ子のリストを降順ソート
on shellSortListDescending(aSortList, aKeyItem)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j gap) and (contents of item aKeyItem of (oBj’s list’s item (j - gap + 1)) < item aKeyItem of temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j - gap + 1)
          
set j to j - gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortListDescending

–入れ子ではないリストの昇順ソート
on shellSortAscending(aSortList)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j gap) and (oBj’s list’s item (j - gap + 1) > temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j - gap + 1)
          
set j to j - gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortAscending

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

2013/08/26 パッケージ内容を表示させつつファイル選択

Mac OS X 10.6あたりから、choose fileやchoose folder、choose from listにいろいろオプション指定が行えるようになってきました。そのあたり、確認するのを怠っていたので再確認のために書いたものです。

choose fileやchoose folder、path toでバンドル内のファイルを選択したり取得できるようになってきたわけで……一昔前までは、バンドルはあくまでファイル(に見えるフォルダ)として扱われ、バンドル内のパスについてはaliasで指定できないことになっていたように記憶しています。

ところが、気がつくとバンドル内のパスも指定できるようになっているというわけで、試しに書いてみました。

おまけに、「info for」命令が「deprecated」とStandardAdditionsのAppleScript用語辞書に書かれていたので、用語辞書に書かれているようにSystem Eventsにファイルのプロパティを求めるようにしてみました。

着実に、「Finderが存在しない環境」でも困らないよう、それに備えたAppleScriptの機能改修が行われているように見えます。

choosefile1.png

▲アプリケーションバンドル内のフォルダから、アイコンファイルの選択が可能

スクリプト名:パッケージ内容を表示させつつファイル選択
set a to choose file with prompt “てすとファイル選択” of type {“com.apple.icns”} with showing package contents and invisibles

–info forだと「deprecated」だとAppleScript用語辞書に書かれているので、あえて変えてみた
tell application “System Events”
  set b to properties of a
end tell

–> {short version:”", container:folder “Macintosh HD:Applications:ebiBookReader.app:Contents:Resources:” of application “System Events”, path:”Macintosh HD:Applications:ebiBookReader.app:Contents:Resources:documenticon.icns”, file type:missing value, sound volume:”Cherry”, physical size:221184, URL:”file://localhost/Applications/ebiBookReader.app/Contents/Resources/documenticon.icns”, id:”documenticon.icns,-100,54651444″, displayed name:”documenticon.icns”, busy status:false, kind:”Apple アイコンイメージ”, creator type:missing value, version:”", name extension:”icns”, POSIX path:”/Applications/ebiBookReader.app/Contents/Resources/documenticon.icns”, name:”documenticon.icns”, modification date:date “2013年8月14日水曜日 9:54:14″, size:219211, class:alias, type identifier:”com.apple.icns”, package folder:false, stationery:false, creation date:date “2013年8月14日水曜日 9:54:14″, default application:alias “Cherry:Applications:Preview.app:” of application “System Events”, visible:true, product version:”"}

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

2013/08/01 指定アプリケーションがオープン可能なファイル種別をリストアップ v3

必要に迫られて、少々場当たり的に書いた、「指定アプリが扱えるファイルのタイプとファイル拡張子のリストをタブ区切りテキストで取得するAppleScript」のバージョンアップ版です。

v2を掲載して、「もうこのプログラムをアップデートすることはないだろー」と思っていたのですが、さらなる追求の手が……

「path to choose application」で選択したアプリのパス(alias)が取れる、とのご指摘。驚いてGoogleで検索してみたものの、その情報を掲載しているページは10件に満たず……まだそんな、隠し機能っぽい記述があったのかと、しみじみと味わわせていただきました。

ということで、滅多に使わない命令「choose application」(AppleScriptを覚えたてのころは、使って遊んでいたような)から「path to」で一気にaliasを取得できるところがみどころです。

ほかは…………まあ、いいじゃないですか。何にもないけど。

スクリプト名:指定アプリケーションがオープン可能なファイル種別をリストアップ v3
–指定アプリのInfo.plistからCFBundleTypeNameとCFBundleTypeExtensionsの情報をタブ区切りテキストで取得するツール v3

script spd
  property aList : {}
  
property aText : “”
end script

–初期化
set aList of spd to {}
set aText of spd to “”

–処理対象アプリケーションの選択
set apPath to path to (choose application with prompt “Doc Typesを取り出す対象のアプリケーションを選択”) –この記述で10行以上のコードが不要に

–指定アプリケーションのバンドル内のInfo.plistのパスを取得
set apPathStr to POSIX path of apPath
set aInfoPath to apPathStr & “Contents/Info.plist”

tell application “System Events”
  set vRec to value of property list file aInfoPath –★【重要】 ここで、”quoted form of”を付けるとエラーになるので注意!!!★
  
  
try
    set dtypeList to CFBundleDocumentTypes of vRec
  on error
    display dialog “とくに、特定のファイルタイプのオープンをサポートしているアプリケーションではないようです”
    
return
  end try
  
end tell

repeat with i in dtypeList
  
  
set j to contents of i
  
  
set tmpStr to recToString(j) of recToStrKit
  
set tmpStr to tmpStr as string
  
  
if tmpStr contains “CFBundleTypeName” then
    –常識的なものへの対処
    
set aName to CFBundleTypeName of j
    
  else if tmpStr contains “CFBundleTypeOSTypes” then
    –Illustrator対策
    
set aaNames to CFBundleTypeOSTypes of j
    
set aName to retArrowText(aaNames, “, “) of me
    
  else if tmpStr contains “LSItemContentTypes” then
    –Excel対策
    
set aaNames to LSItemContentTypes of j
    
set aName to retArrowText(aaNames, “, “) of me
    
  end if
  
  
  
try
    set extName to CFBundleTypeExtensions of j
  on error
    set extName to {“”}
  end try
  
  
if length of extName > 1 then
    set extStr to retArrowText(extName, “, “) of me
  else
    set extStr to contents of first item of extName
  end if
  
  
–拡張子の指定のあるものだけをレポート対象とする
  
if extStr is not equal to “” then
    set aText of spd to aText of spd & aName & tab & extStr & return
  end if
  
end repeat

–あとかたづけ
set aList of spd to {}

return contents of aText of spd

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

script recToStrKit
  
  
–エラートラップを使って、わざとエラーを発生させ、エラーメッセージからレコードをstringに変換する
  
on recToString(aRec)
    
    
–レコードを無理矢理stringにcastして、エラーメッセージを取得する
    
try
      set a to aRec as string –ここでエラー発生
    on error aMes
      set a to aMes
    end try
    
    
–エラーメッセージ文字列から、元のレコードの情報を組み立てる
    
set b to trimStrFromTo(a, “{”, “}”)
    
set b to “{” & b & “}”
    
    
return b
    
  end recToString
  
  
  
on trimStrFromTo(aStr, fromStr, toStr)
    –fromStrは前から探す
    
if fromStr is not equal to “” then
      set sPos to (offset of fromStr in aStr) + 1
    else
      set sPos to 1
    end if
    
    
–toStrは後ろから探す
    
if toStr is not equal to “” then
      set b to (reverse of characters of aStr) as string
      
set ePos to (offset of toStr in b)
      
set ePos to ((length of aStr) - ePos)
    else
      set ePos to length of aStr
    end if
    
set aRes to text sPos thru ePos of aStr
    
    
return aRes
    
  end trimStrFromTo
  
end script

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

2013/07/31 指定アプリケーションがオープン可能なファイル種別をリストアップ v2

必要に迫られて、少々場当たり的に書いた、「指定アプリが扱えるファイルのタイプとファイル拡張子のリストをタブ区切りテキストで取得するAppleScript」のバージョンアップ版です。

由緒正しき「作り捨てScript」(あんまり用途がないので保存するのすら惜しいレベル)なので、まさかバージョンアップすることなどないと思っていたのですが……いろいろと指摘があり、処理がいまいちな点を書き換えてみました。

 Info.plistをコピーしてから読み込み → 直接読み込み
 ぼんやりとエラー対策していた → Recordを文字列化して指定ラベルの値があるかどうか事前にチェック

直してみて気付いた点は、System Eventsでバンドル内のInfo.plistファイルをPOSIX pathで直接指定できるものの、この際にパスを「quoted form of」でクォートするとエラーになるということです(10.8)。この発見が、本バージョンで唯一の収穫ということに。

スクリプト名:指定アプリケーションがオープン可能なファイル種別をリストアップ v2
–指定アプリのInfo.plistからCFBundleTypeNameとCFBundleTypeExtensionsの情報をタブ区切りテキストで取得するツール v2

script spd
  property aList : {}
  
property aText : “”
end script

–初期化
set aList of spd to {}
set aText of spd to “”

–処理対象アプリケーションの選択
set anApp to choose application with prompt “Doc Typesを取り出す対象のアプリケーションを選択”

–処理対象のアプリケーションの名称を取得
try
  tell anApp
    launch –起動してみる(めっちゃ重要)
    
set aName to name –名称取得
  end tell
on error
  display dialog “プロセス起動も名称取得もできなかったので処理終了”
  
return
end try

–起動したアプリのプロセス特定 → ファイルパスの特定
tell application “System Events”
  set aProc to every process whose name is aName
  
if length of aProc = 0 then
    display dialog “No Hit”
    
return
  end if
  
  
set aaProc to contents of first item of aProc
  
tell aaProc
    set apPath to application file –Path to application file as alias
  end tell
end tell

–指定アプリケーションのバンドル内のInfo.plistのパスを取得
set apPathStr to POSIX path of apPath
set aInfoPath to apPathStr & “Contents/Info.plist”

tell application “System Events”
  set vRec to value of property list file aInfoPath –★【重要】 ここで、”quoted form of”を付けるとエラーになるので注意!!!★
  
  
try
    set dtypeList to CFBundleDocumentTypes of vRec
  on error
    display dialog “とくに、特定のファイルタイプのオープンをサポートしているアプリケーションではないようです”
    
return
  end try
  
end tell

repeat with i in dtypeList
  
  
set j to contents of i
  
  
set tmpStr to recToString(j) of recToStrKit
  
set tmpStr to tmpStr as string
  
  
if tmpStr contains “CFBundleTypeName” then
    –常識的なものへの対処
    
set aName to CFBundleTypeName of j
    
  else if tmpStr contains “CFBundleTypeOSTypes” then
    –Illustrator対策
    
set aaNames to CFBundleTypeOSTypes of j
    
set aName to retArrowText(aaNames, “, “) of me
    
  else if tmpStr contains “LSItemContentTypes” then
    –Excel対策
    
set aaNames to LSItemContentTypes of j
    
set aName to retArrowText(aaNames, “, “) of me
    
  end if
  
  
  
try
    set extName to CFBundleTypeExtensions of j
  on error
    set extName to {“”}
  end try
  
  
if length of extName > 1 then
    set extStr to retArrowText(extName, “, “) of me
  else
    set extStr to contents of first item of extName
  end if
  
  
–拡張子の指定のあるものだけをレポート対象とする
  
if extStr is not equal to “” then
    set aText of spd to aText of spd & aName & tab & extStr & return
  end if
  
end repeat

–あとかたづけ
set aList of spd to {}

return contents of aText of spd

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

script recToStrKit
  
  
–エラートラップを使って、わざとエラーを発生させ、エラーメッセージからレコードをstringに変換する
  
on recToString(aRec)
    
    
–レコードを無理矢理stringにcastして、エラーメッセージを取得する
    
try
      set a to aRec as string –ここでエラー発生
    on error aMes
      set a to aMes
    end try
    
    
–エラーメッセージ文字列から、元のレコードの情報を組み立てる
    
set b to trimStrFromTo(a, “{”, “}”)
    
set b to “{” & b & “}”
    
    
return b
    
  end recToString
  
  
  
on trimStrFromTo(aStr, fromStr, toStr)
    –fromStrは前から探す
    
if fromStr is not equal to “” then
      set sPos to (offset of fromStr in aStr) + 1
    else
      set sPos to 1
    end if
    
    
–toStrは後ろから探す
    
if toStr is not equal to “” then
      set b to (reverse of characters of aStr) as string
      
set ePos to (offset of toStr in b)
      
set ePos to ((length of aStr) - ePos)
    else
      set ePos to length of aStr
    end if
    
set aRes to text sPos thru ePos of aStr
    
    
return aRes
    
  end trimStrFromTo
  
end script

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

2013/07/30 指定アプリケーションがオープン可能なファイル種別をリストアップ

必要に迫られて、少々場当たり的に書いた、「指定アプリが扱えるファイルのタイプとファイル拡張子のリストをタブ区切りテキストで取得するAppleScript」です。書くのに30分ぐらいしかかかっていないと思います。

指定アプリのInfo.plistを……バンドル内に存在する状態でオープンするのは無理なので、いちどテンポラリフォルダにコピーして、System Events経由で値の取得を行い、CFBundleDocumentTypesのエントリから、CFBundleTypeNameとCFBundleTypeExtensionsの情報をタブ区切りテキストで取得します。

ap1.png
▲処理対象のアプリケーションを選択して……

ap2.png
▲AppleScriptエディタの「結果」欄にデータ出力する

正直、Photoshopの情報だけリスト化することを目指して作ったので、どんなアプリに対してでも使えるようには作っていません。いえ、作っても意味がないというべきなのか、万能ツールはねらわずに「作り捨てツール」のレベルなのでそんなもんです。

■うまくデータを引き出せる例
Adobe Photoshop, Illustrator, InDesign, AppleScriptエディタ、Safari、連絡先(アドレスブック)など

■データを引き出せない例(エラーになる)
iTunes、Mail.app、Terminal.app

■そもそも書類をオープンするようになっていない例
AppleScript Runner、Automator Runner

Photoshopに対して大量の画像ファイルの一括変換を行わせるツールを作っていたときに、ドラッグ&ドロップで処理を受け付けるべきファイルと、受け付けるべきではない(画像以外の)ファイルの見通しを立てるために資料を作っていました。

ap4.png

PhotoshopのInfo.plistをXcodeでひらいて、Keynoteの表にコピペしていくという地味で根気の必要な作業です。

ap3.png

途中まで(手で)作っていたものの……

「Photoshopの100個以上もあるファイルタイプを全部コピペで資料化するのはイヤだ!」

と、ブチ切れ。方針転換してAppleScriptで書きました。実行したら一瞬で終了。

本ツールで作業量を圧倒的に減らすことができたものの、活躍する機会はあまりなさそうです。

スクリプト名:指定アプリケーションがオープン可能なファイル種別をリストアップ
–指定アプリのInfo.plistからCFBundleTypeNameとCFBundleTypeExtensionsの情報をタブ区切りテキストで取得するツール

script spd
  property aList : {}
  
property aText : “”
end script

–初期化
set aList of spd to {}
set aText of spd to “”

–処理対象アプリケーションの選択
set anApp to choose application with prompt “Doc Typesを取り出す対象のアプリケーションを選択”

–処理対象のアプリケーションの名称を取得
try
  tell anApp
    
    
launch –起動してみる(めっちゃ重要)
    
    
set aName to name –名称取得
    
  end tell
  
on error
  display dialog “プロセス起動も名称取得もできなかったので処理終了”
  
return
end try

–起動したアプリのプロセス特定 → ファイルパスの特定
tell application “System Events”
  set aProc to every process whose name is aName
  
if length of aProc is not equal to 1 then
    display dialog “No Hit”
    
return
  end if
  
  
set aaProc to contents of first item of aProc
  
tell aaProc
    set apPath to application file –Path to application file as alias
  end tell
end tell

–指定アプリケーションのバンドル内のInfo.plistのパスを取得
set apPathStr to POSIX path of apPath
set aConPath to quoted form of (apPathStr & “Contents/”)
set aifoPfetch to aConPath & “Info.plist”

set aRes to do shell script “ls “ & aifoPfetch
set shelList to paragraphs of aRes

if length of shelList > 1 then
  set shelRes to contents of first item of (choose from list shelList)
else
  set shelRes to contents of first item of shelList
end if

–デスクトップ上にコピーする際のファイルパスを生成
set aRandomName to (POSIX path of (path to temporary items from user domain)) & (do shell script “uuidgen”) & “.plist”

do shell script “cp “ & quoted form of shelRes & ” “ & quoted form of aRandomName

set aRandomAlias to (POSIX file aRandomName) as alias

tell application “System Events”
  set vRec to value of property list file (aRandomAlias as string)
  
try
    
    
set dtypeList to CFBundleDocumentTypes of vRec
    
  on error
    do shell script “rm “ & quoted form of aRandomName
    
display dialog “とくに、特定のファイルタイプのオープンをサポートしているアプリケーションではないようです”
    
return
  end try
end tell
–> {{CFBundleTypeExtensions:{”psd”, “pdd”}, CFBundleTypeOSTypes:{”8BPS”, “8BIM”}, CFBundleTypeName:”Adobe Photoshop file”, CFBundleTypeIconFile:”PS_PrimaryFileIcon.icns”, CFBundleTypeRole:”Editor”}………}

repeat with i in dtypeList
  try
    set aName to CFBundleTypeName of i
    
  on error
    –Illustrator対策
    
set aaNames to CFBundleTypeOSTypes of i
    
    
if length of aaNames > 1 then
      set aName to retArrowText(aaNames, “, “) of me
    else
      set aName to contents of first item of aaNames
    end if
    
  end try
  
  
  
try
    set extName to CFBundleTypeExtensions of i
  on error
    set extName to {“”}
  end try
  
  
if length of extName > 1 then
    set extStr to retArrowText(extName, “, “) of me
  else
    set extStr to contents of first item of extName
  end if
  
  
–拡張子の指定のあるものだけをレポート対象とする
  
if extStr is not equal to “” then
    set aText of spd to aText of spd & aName & tab & extStr & return
  end if
  
end repeat

–あとかたづけ
do shell script “rm “ & quoted form of aRandomName
set aList of spd to {}

return contents of aText of spd

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

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

2013/07/19 Desktopのプロパティを取得、設定

海外のMLをのぞいていたら、System Events経由でDesktopのプロパティを取得できることを(いまさらながらに)見つけました。その内容のまとめです。

Classic Mac OSの時代からMac OS Xの時代に切り替わったあたりから、それまでFinderに所属していた命令やオブジェクトが、続々とSystem Eventsに移管されてきました。電源オフやスリープなどの命令が入っている「Power Suites」ももともとはFinderに所属しており、まだFinderの用語辞書にその痕跡が残っていますが、いつか完全にFinderから消える日がくることでしょう。

とりあえず、Desktopのプロパティの取得を試してみました。

スクリプト名:Desktopのプロパティを取得
tell application “System Events”
  set dCount to count every desktop
  
  
repeat with i from 1 to dCount
    tell desktop i
      properties
    end tell
  end repeat
  
end tell

–> {display name:”W2442″, id:458588002, change interval:1800.0, name:”W2442″, picture:file “Cherry:Library:Desktop Pictures:Bahamas Aerial.jpg”, class:desktop, pictures folder:file “Cherry:Users:maro:Pictures:”, translucent menu bar:true, random order:false, picture rotation:0}

–> {display name:”カラー LCD”, id:69731200, change interval:1800.0, name:”カラー LCD”, picture:file “Cherry:Library:Desktop Pictures:Grass Blades.jpg”, class:desktop, pictures folder:file “Cherry:Library:Desktop Pictures:”, translucent menu bar:true, random order:false, picture rotation:0}

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

Desktopの数というのは、つまりモニターの数を意味しています。

desktop1.png

詳細な情報を取得できるため、なかなか面白いところです。「change interval」という、見慣れない属性がありますが、これはデスクトップピクチャの変更間隔です。1800秒ということは、30分ですね。

もちろん、取得だけでなく設定も行えます。current desktopというのが、primary desktopのようで……つまり、メニューバーが存在しているメインの画面です。「translucent menu bar」という属性(メニューバーの透過表示の制御)があり、これがr/wできるので試してみました。

実行するたびに、メニューバーが透過/非透過と切り替わります。

Mac OS X 10.4.11ではSystem Eventsにdesktopオブジェクトの定義そのものが存在せず、10.5.8ではdesktopオブジェクトは存在するものの、「translucent menu bar」の属性が存在していませんでした。10.6以降の環境で動作することを確認しています。

スクリプト名:メニューバーの透過を切り替える
tell application “System Events”
  tell current desktop –Primary Desktopのこと
    properties
    
–> {display name:”W2442″, id:458588002, change interval:1800.0, name:”W2442″, picture:file “Cherry:Library:Desktop Pictures:Bahamas Aerial.jpg”, class:desktop, pictures folder:file “Cherry:Users:maro:Pictures:”, translucent menu bar:true, random order:false, picture rotation:0}
    
    
set transF to translucent menu bar
    
set transF to not transF –論理を反転
    
set translucent menu bar to transF
  end tell
end tell

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

2013/05/24 Finder上で選択中のファイルをPreviewでオープンして保存してクローズ

Finder上で選択中のファイル(たぶんPDF)をPreview.appでオープンして、保存してクローズ……を繰り返すAppleScriptです。

PhotoshopでPDFを加工したところ、そのままではファイルサイズが大きく、古いOS(Mac OS X 10.4.11とか)では内容を確認できない状態でした。

……ちょっと困りました。そこで、OS X 10.8上のPreview.appでファイルを保存し直したところ、ファイルサイズも小さくなり、古いOSでもオープンできるようになりました。

何か、ほかにも回避方法はありそうですが……とりあえず、本AppleScriptによって、Finder上でPhotoshopによる加工を行ったPDFを選択しておき、Scriptを実行することですべて保存し直します。

なお、本AppleScriptはGUI Scriptingを利用しているため、あらかじめシステム環境設定の「アクセシビリティ」で「補助装置にアクセスできるようにする」にチェックを入れておく必要があります。また、将来のOSバージョンアップによってPreview.appのメニュー内容が変更になった場合には、そのままでは動かず修正(メニューアイテム番号部分のみ)が必要になる可能性が高いです。

スクリプト名:Finder上で選択中のファイルをPreviewでオープンして保存してクローズ
tell application “Finder”
  set aList to selection as alias list
end tell

repeat with i in aList
  
  
set j to contents of i
  
set jj to j as string
  
  
–Preview.appで選択されたファイルをオープンする
  
set appBundleID to “com.apple.Preview”
  
tell application “Finder”
    open file jj using application file id appBundleID
  end tell
  
  
delay 0.1
  
  
–Preview.appでファイル保存→クローズを行う
  
activate application “Preview”
  
tell application “System Events”
    tell process “プレビュー”
      click menu item 8 of menu 1 of menu bar item 3 of menu bar 1 –保存
    end tell
  end tell
  
  
delay 0.1
  
  
tell application “System Events”
    tell process “プレビュー”
      click menu item 5 of menu 1 of menu bar item 3 of menu bar 1 –閉じる
    end tell
  end tell
  
end repeat

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

2011/10/18 指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v3

バンドルIDを指定してアプリケーションのパスを求め、その中のローカライズ文字列テーブルから指定ラベルに該当する文字を取り出すAppleScriptの改良版です。

プロセスを確認して、起動中であればプロセスから情報を取得。起動中ではない場合には、Finder経由で実行ファイルのパスを求めるようにしています。

スクリプト名:指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v3

set aRes to retLocalizedStringFromApp("135.006", "com.apple.itunes") of me
–> "ライブラリ"–Japanese
–> "LIBRARY"–English
–> "BIBLIOTHÈQUE"–French
–> ""–Simply Chinese
–> "資料庫"–Traditional Chinese
–> "MEDIATHEK"–Deutsch

–指定バンドルIDのアプリケーション内のResourcesフォルダの中の現在のロケールのフォルダ内のLocalizable.strings内の指定タグに対応する値を取得
–iTunesのような「不適切なローカライズ」に対応するために、リソース内のローカライズデータからオブジェクト名を取得
on retLocalizedStringFromApp(locLabel, bundleID)
  
  
set pRes to retExistenceOfProcessByBundleID(bundleID) of me
  
  
if pRes is not equal to false then
    –指定Bundle IDのプロセスが起動していた場合
    
tell application "System Events"
      tell pRes
        set appFile to application file
      end tell
    end tell
    
  else
    –指定Bundle IDのプロセスが起動していなかった場合
    
tell application "Finder"
      try
        set appFile to application file id bundleID
      on error
        return
      end try
    end tell
    
    
set appFile to appFile as alias
  end if
  
  
  
set aStr to localized string locLabel in bundle appFile
  
end retLocalizedStringFromApp

–指定のバンドルIDのプロセスが起動していればプロセスへの参照を返す、なければfalseを返す
on retExistenceOfProcessByBundleID(bundleID)
  tell application "System Events"
    set aProc to every process whose bundle identifier is equal to bundleID
    
if aProc = {} then return false
    
    
set aProc to contents of first item of aProc
    
return aProc
  end tell
end retExistenceOfProcessByBundleID

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

本ルーチンを使って、iTunesの「ライブラリ」に該当する文字列を取り出すテストを行い、実際に使用ユーザー環境の言語を変更してログインし直し、各言語で動作確認を行ってみました。

スクリプト名:iTunes_control_Japanese
tell application “iTunes”
  tell source “ライブラリ”
    tell playlist “ライブラリ”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_English
tell application “iTunes”
  tell source “LIBRARY”
    tell playlist “LIBRARY”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_Deteuch
tell application “iTunes”
  tell source “MEDIATHEK”
    tell playlist “MEDIATHEK”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_French
tell application “iTunes”
  tell source “BIBLIOTHÈQUE”
    tell playlist “BIBLIOTHÈQUE”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_Chinese (simplified)
tell application “iTunes”
  tell source
    tell playlist
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_Chinese (traditional)
tell application “iTunes”
  tell source “資料庫”
    tell playlist “資料庫”
      count every track
    end tell
  end tell
end tell

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

……で、冒頭のScriptを使うと、これらの各言語環境ごとにバラバラのオブジェクト名を記述しなければならなかった部分が、1本のScriptでカバーできるはずです。

スクリプト名:指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v3.1
–すべての言語環境でこのプログラムに統一できるはず
set aRes to retLocalizedStringFromApp(“135.006″, “com.apple.itunes”) of me

tell application “iTunes”
  tell source aRes
    tell playlist aRes
      count every track
    end tell
  end tell
end tell

–指定バンドルIDのアプリケーション内のResourcesフォルダの中の現在のロケールのフォルダ内のLocalizable.strings内の指定タグに対応する値を取得
–iTunesのような「不適切なローカライズ」に対応するために、リソース内のローカライズデータからオブジェクト名を取得
on retLocalizedStringFromApp(locLabel, bundleID)
  
  
set pRes to retExistenceOfProcessByBundleID(bundleID) of me
  
  
if pRes is not equal to false then
    –指定Bundle IDのプロセスが起動していた場合
    
tell application “System Events”
      tell pRes
        set appFile to application file
      end tell
    end tell
    
  else
    –指定Bundle IDのプロセスが起動していなかった場合
    
tell application “Finder”
      try
        set appFile to application file id bundleID
      on error
        return
      end try
    end tell
    
    
set appFile to appFile as alias
  end if
  
  
  
set aStr to localized string locLabel in bundle appFile
  
end retLocalizedStringFromApp

–指定のバンドルIDのプロセスが起動していればプロセスへの参照を返す、なければfalseを返す
on retExistenceOfProcessByBundleID(bundleID)
  tell application “System Events”
    set aProc to every process whose bundle identifier is equal to bundleID
    
if aProc = {} then return false
    
    
set aProc to contents of first item of aProc
    
return aProc
  end tell
end retExistenceOfProcessByBundleID

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

2011/10/18 指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v2

指定アプリの内部リソースから指定ラベルに該当する文字列を取り出すAppleScriptの改良版です。アプリケーション名を指定してプロセスを取得するのではなく、Finderに対してアプリケーションのバンドルIDを指定してアプリケーションの実行ファイルのパスを求めるようにして処理するものです。

ただ、Mac OS X 10.6上だとFinderへのAppleScriptからのアクセスが途中からとても遅くなってしまったので、なんでもかんでもFinderに問い合わせるのは避けたいところです。

スクリプト名:指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v2

set aRes to retLocalizedStringFromApp("135.006", "com.apple.itunes") of me

on retLocalizedStringFromApp(locLabel, appID)
  
  
tell application "Finder"
    try
      set appFile to application file id appID
    on error
      return
    end try
  end tell
  
  
set appFile to appFile as alias
  
  
set aStr to localized string locLabel in bundle appFile
  
end retLocalizedStringFromApp

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

2011/10/18 指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する

Amazonダウンローダー内でAppleScriptを使っている箇所があり、案の定、オブジェクト名までローカライズされているiTunesの特性を理解せずに作られているために、日本語環境ではまともに動かなくて大笑いしましたが……このような悲劇が起こらないように、いろいろ考えておりました。

結局のところ、アプリケーションのバンドル内のResourcesフォルダの各言語フォルダの中に入っているLocalizable.stringsファイル内から該当するデータを取り出せればよいのだろうか、と考えました。

locali.jpg

そこで、実際にLocalizable.stringsを調査して、実際にオブジェクト名に該当するものを探しだし、ラベルを指定して取り出せるようにしてみました。

Localizable.stringsには文字定数とか画面に表示する文字列なんかを入れておくわけで、このケースでも画面上に「ライブラリ」と表示するためのデータが格納されているわけですが、それがAppleScriptのオブジェクト名と同じであるために、結果オーライで取り出してみることにしました。

本バージョンでは、アプリケーション名とLocalizable.strings内のラベルを指定します。対象のアプリケーションが起動していることが実行条件です。

スクリプト名:指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する

set aRes to retLocalizedStringFromApp(“135.006″, “iTunes”) of me

on retLocalizedStringFromApp(locLabel, appName)
  
  
launchAnApp(appName) of me
  
  
tell application “System Events”
    set aProc to process appName
    
if aProc = “” then return
    
    
tell aProc
      set appPath to application file
    end tell
  end tell
  
  
set aStr to localized string locLabel in bundle appPath –ライブラリ
  
end retLocalizedStringFromApp

on launchAnApp(appName)
  tell application appName to launch
end launchAnApp

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

2010/03/26 現在編集中のXcodeプロジェクトのビルドターゲットが生成したpreferenceファイルを削除する v2

Xcode上で編集中のプロジェクトのビルドターゲットがテストラン時に生成したplistファイルを削除するAppleScriptです。Xcode 3.1.4をターゲットに作成したものですが、Xcode 3.2.xでも多分動くことでしょう。

AppleScriptによるXcodeの自動化というのは、本当にやりたい処理があってもXcodeのAppleScript対応機能が不十分で実装できないことが多くて実現できないケースが多いのですが……このケースではキレイにできました。Xcodeの単純なプロジェクト(ビルドターゲットが1つだとか、一般的なデスクトップアプリケーションのプロジェクトだとか)向けに作ったので、プラグインとかkextとかのプロジェクトまでは考慮していません。

AppleScriptからXcodeに問い合わせてプロジェクトのタイプなども取得できるとよいのですが……そういう「実践的な機能」というのが載ってこないのがXcodeのAppleScript辞書の不思議なところです。絶対に、AppleScriptの記述経験がほとんどないエンジニアが実装を行わされているに違いない、と思わせるものがあります。

Xcode(AppleScript StudioとかAppleScriptObjC)でプログラムを組んでいて、テストラン時に生成されたplistファイルが邪魔になってきちんと動作検証できないケースがあります。本来はうまく動いてはいけないものが、過去にテストランしたときのplistファイルが残ってしまっていたために「動いてしまった」とか。

そのため、plistファイルを手でいちいち消していました。Xcodeのクリーンコマンドは、ビルドフォルダ内のファイルは消去してくれますが、plistファイルは消してくれません。割とよく使う処理だったので、AppleScriptで自動化してみました。なにげに便利です。

スクリプト名:現在編集中のXcodeプロジェクトのビルドターゲットが生成したpreferenceファイルを削除する v2
–現在編集中のXcodeプロジェクトのパス情報を取得
tell application “Xcode”
  tell project 1
    set projPath to real path
  end tell
end tell

–現在編集中のプロジェクトに含まれるInfo.plistファイルを検出
set projPath to POSIX file projPath

tell application “Finder”
  set parantFol to (folder of file projPath) as alias
  
tell folder parantFol
    set infoP to exists of file “info.plist”
    
if infoP = false then
      display dialog “現在編集中のプロジェクトにはInfo.plistが入っていません。” buttons {“OK”} default button 1 with icon 1
      
return
    end if
  end tell
end tell

–Info.plistファイルからバンドル情報を取得する
set pListPath to (parantFol as string) & “Info.plist”
tell application “System Events”
  set vRec to value of property list file (pListPath as string) –plist fileから値を読み取る
end tell
set infoRes to |CFBundleIdentifier| of vRec

–plistファイルを消す
set aPath to (path to preferences from user domain) as string
set infoPlistPath to aPath & infoRes & “.plist”

try
  do shell script “rm -f “ & quoted form of POSIX path of infoPlistPath
  
tell application “Xcode”
    activate
    
display dialog “plistファイルを消去しました” buttons {“OK”} default button 1 with icon 1
  end tell
on error
  tell application “Xcode”
    activate
    
display dialog “plistファイルの消去に失敗しました” buttons {“OK”} default button 1 with icon 1
  end tell
end try

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

2010/03/17 m2TVの録画ライブラリ情報を取得する

アイ・オー・データ機器のUSB地デジチューナー「m2TV」の録画ずみライブラリの情報を取得するAppleScriptです。

m2TVアプリケーションがAppleScript側に提供している機能は、番組録画予約だけですが、m2TVアプリケーションのライブラリ情報ファイル(plist形式)にAppleScriptから直接アクセスすることで、ご覧のようにライブラリ情報を取得しています。

スクリプト名:m2TVの録画ライブラリ情報を取得する
set aRes to getM2TV_LibData() of me
–>
(*
{{eventDate:date “2010年3月3日水曜日 21:00:00″, durationSeconds:3240, sName:”テレビ朝日”, pTitle:”相棒8 #18”, eDesc:”警視庁一の異端児・杉下右京(水谷豊)と突如特命係に左遷された神戸尊(及川光博)。尊は上層部からの命で右京を調査するため特命係へ。この新しい相棒から目が離せない!”, eDetail:”

【番組内容】
第18話『右京、風邪をひく』
山中で他殺体が発見された。捜査一課の伊丹は被害者の近所に住むジュン(東風万智子)が怪しいと睨み事情をきくと犯行を自供。鼻高々の伊丹だが右京(水谷豊)と尊(及川光博)は何故か微笑み合う。自供の裏にはもうひとつの事件があった!

【出演者】
水谷豊・及川光博・益戸育江
川原和久・大谷亮介・山中崇史・山西惇・六角精児

【ゲスト】
東風万智子・滝直希

【スタッフ】
●脚本:古沢良太
●監督:東伸児
●ゼネラルプロデューサー:松本基弘(テレビ朝日)
●プロデューサー:伊東仁(テレビ朝日)・西平敦郎(東映)・土田真通(東映)

【音楽】
池頼広
※相棒8オリジナル・サウンドトラック好評発売中!

【おしらせ】
右京ティーカップ絶賛発売中!
PCサイトと携帯サイトも充実!
PC: http://www.tv−asahi.co.jp/aibou/
携帯:メニュー ⇒ テレビ ⇒ テレビ朝日 ⇒ 相棒”}}
*)

–m2TVの録画ライブラリ情報を取得する
on getM2TV_LibData()
  set docFol to (path to documents folder) as string
  
set prgFilePath to docFol & “MacTV:MacTVLibrary.plist”
  
  
–設定ファイルが存在しなければリターン
  
tell application “Finder”
    set aRes to exists of file prgFilePath
  end tell
  
if aRes = false then return
  
  
–m2TVの録画ライブラリ情報ファイルから部分的に情報を読み込む
  
set prefsFile to prgFilePath as alias
  
tell application “System Events”
    set prgList to {}
    
    
set vRec to value of property list file (prefsFile as string) –plist fileから値を読み取る
    
repeat with i in vRec
      set j to contents of i
      
      
set eDate to eventDate of eventInfo of j
      
set stationName to station of j
      
set progTitle to |title| of j
      
set aDuration to eventDuration of eventInfo of j
      
set eventDescDat to eventDesc of eventInfo of j
      
set eventDetail to eventDetails of eventInfo of j
      
      
set the end of prgList to {eventDate:eDate, durationSeconds:aDuration, sName:stationName, pTitle:progTitle, eDesc:eventDescDat, eDetail:eventDetail}
      
      
    end repeat
  end tell
  
  
return prgList
  
end getM2TV_LibData

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

2010/03/16 m2TVの録画スケジュール情報を取得する

アイ・オー・データ機器のUSB地デジチューナー「m2TV」でテレビ録画予約情報を取得するAppleScriptです。

m2TVのアプリケーション自体には、AppleScriptには指定時間帯/チャンネルの録画依頼機能しか開放されていません。録画予約を行っても、それが実際に予約されたのかどうかという結果も返ってきません。true/falseぐらいは返ってきてほしいものです。

そこで、m2TVアプリの設定ファイルをAppleScriptで直接読み込むテストを行い、録画スケジュール情報を取り出してみました。ご覧のとおり、情報を取得できています。

録画予約を行った後に、本ルーチンを併用して録画予約が確実に行えたかを確認することもできますし、録画予約を行う前に予約状況を確認することも可能です。

あとは、1週間分のTV番組表からiEPGの録画予約ファイルをすべてダウンロードし、AppleScript側で自力で番組表データをリストに仕上げ、さまざまなクエリーで検索できるようにするとよいでしょう。そのようなルーチンがすでに存在しているといいのですが……。

スクリプト名:m2TVの録画スケジュール情報を取得する
set aRes to getM2TV_recSchedule() of me
–> {{sDate:date “2010年3月16日火曜日 22:25:00″, eDate:date “2010年3月16日火曜日 22:50:00″, durationSeconds:1500, sName:”NHK教育・東京”, pTitle:”知る楽 歴史は眠らない“貧困”国家 日本の深層 第3回「見えなくなった貧困」”}, {sDate:date “2010年3月17日水曜日 0:59:00″, eDate:date “2010年3月17日水曜日 1:29:00″, durationSeconds:1800, sName:”日本テレビ”, pTitle:”レコ☆Hits!”}}

–m2TVの録画予約スケジュールを取得する
on getM2TV_recSchedule()
  set docFol to (path to documents folder) as string
  
set prgFilePath to docFol & “MacTV:MacTVSchedule.plist”
  
  
–設定ファイルが存在しなければリターン
  
tell application “Finder”
    set aRes to exists of file prgFilePath
  end tell
  
if aRes = false then return
  
  
–m2TVの録画情報ファイルから部分的に情報を読み込む
  
set prefsFile to prgFilePath as alias
  
tell application “System Events”
    set prgList to {}
    
    
set vRec to value of property list file (prefsFile as string) –plist fileから値を読み取る
    
repeat with i in vRec
      set j to contents of i
      
set startDate to |start| of j
      
set endDate to |end| of j
      
set stationName to station of j
      
set progTitle to |title| of j
      
set aDuration to eventDuration of eventInfo of j
      
set the end of prgList to {sDate:startDate, eDate:endDate, durationSeconds:aDuration, sName:stationName, pTitle:progTitle}
    end repeat
  end tell
  
  
return prgList
  
end getM2TV_recSchedule

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

2009/12/12 選択したアプリケーションのInfo.plistを読んで、実行バイナリの名称を取得する

選択したアプリケーションファイルのバンドル内のInfo.plistを読んで、実行バイナリの名称を取得するAppleScriptです。

スクリプト名:選択したアプリケーションのInfo.plistを読んで、実行バイナリの名称を取得する
(*
選択したアプリケーションのInfo.plistを読んで、
実行バイナリの名称を取得する
*)

set a to choose file
set aP to POSIX path of a
set infoPath to aP & "Contents/Info.plist"

tell application "System Events"
  set infoplistFile to contents of property list file infoPath
  
set anExecutable to value of property list item "CFBundleExecutable" of infoplistFile
end tell

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

2009/12/12 PlistファイルをParseして返す

PlistファイルをParseして返すAppleScriptです。

各アプリケーションのプロパティ内容は~/Library/Preferencesフォルダにplistファイルで書かれることが多く、その内容を読めると役に立つこと「も」あります。

どちらかといえば、既存のアプリケーションについてはshellのdefaults readコマンドで読むことが多く、System Eventsに命令を送ってプロパティの内容を読み取るのは、自分で作ったAppleScript Studioアプリケーションの場合が多いように感じます。

スクリプト名:PlistファイルをParseして返す
set anAlias to choose file
set aRes to parseAndRetPlistEntryFromFile(anAlias) of me

–PlistファイルをParseして返す
on parseAndRetPlistEntryFromFile(aFile)
  set f to POSIX path of aFile
  
set res to {}
  
try
    tell application “System Events”
      set plif to property list file f
      
set pitm to every property list item of plif
      
repeat with p in pitm
        set end of res to {name, value} of p
      end repeat
    end tell
  on error
    return {}
  end try
  
return res
end parseAndRetPlistEntryFromFile

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