Archive for 4月, 2016

2016/04/30 WikipediaのAppleScriptの項目を大幅書き換え

Twitter上で大学教員の方とかベテランプログラマーの方々が、AppleScriptについて判で押したように同じような間違ったことを吹聴しているのをたびたび見かけ、

「この世界のどこかに、古くて間違った情報ばかり流している悪質情報サイトがあるにちがいない」

と思っており、先日それをとうとう見つけました。Wikipediaです。

WikipediaのAppleScriptの項目の内容がとても古く、読んでいてめまいがするほど。AppleのWebサイト内のリンク先もすべてリンク切れで、まるで廃墟のようでした。

さらに、関連するリンク先のキーワードの内容にも技術的な間違いがてんこもり。Mac OS Xの項目のプログラミング言語の項目にAppleScriptがないどころか、Swiftまで書かれていない始末(Swift自体の項目はある)。

そこで、「近代化改修」という名の下にこの項目を大幅に書き換えました。Wikipedia独特の名称記述ルールや、リンクのためのタグ、外部のページをリンクするさいの独自ルールなどに目が回りそうになりましたが、覚えればなんということはありません。

だいたい、HyperCardなんていま使っている人はほとんどいないですし、DialogDirector OSAXなんてWeb上で見当たらないし、REALbasicでインタフェース作成なんてほとんどやってないし名前までXojoに変わってしまいましたし、「AppleScript日本語形式」なんて20年近く前の遺物をいまだに掲載している意味がわかりません(当時ですら、「これはありえない」と感じて英語形式を勉強しだしたほど)。

さらに、AppleScriptObjCについての言及など一言もなかったので、時代的には8〜10年ぐらい遅れている内容でした。

そのため、わざわざWikipedia向けに文章をフルスクラッチで書き起こしました。1年ごとに(OSアップデートのたびに)チェックは必要と思われますが、そのあたりはWikipediaのREST APIにAppleScript経由で直接アクセスし、リンク切れなどを自動で検出するようにしておけばよいと思われます。

2016/04/30 技術系同人誌即売会「技術書典」B-01ブースにて出展

6月25日(土)に秋葉原の通運会館で行われる技術系同人誌即売会「技術書典」に応募し、当選いたしました。

地下1階のB-01ブースでPiyomaru SoftwareはAppleScript関連のDVD-R本を発売いたします。紙ではありません。

そのため、事前におおまかな内容を確認できる、紙の見本誌を若干数作成して持ち込む予定です(その場で見るような場所がない可能性もあるので、事前にWeb上で一部を公開するかも)。以前に応募したQ&Aについては、これまでにTwitter上に流れていた質問を拾い上げて40本ぐらいはたまりました(継続して募集中です)。

最新の情報を反映させたAppleScript情報本というコンセプトで企画を練っており、

 ・最新情報だけに的をしぼったAS最新情報本
 ・わかりやすく段階を上げられる「挫折しにくいAS入門」

の2パターンのうちどちらか、あるいはこれらの折衷案を検討中です。

オマケとして、日々のAppleScript作成に威力を発揮している「コンテクストメニューアシスタント」を同梱します。というよりも、このコンテクストメニューアシスタントを前提とした本になる見込みです。

2016/04/27 AppleScriptから電話をかける v2

同一WiFiネットワーク内にある自分の(Macとひもづけした)iPhoneを利用して、Macから電話をかけるAppleScriptの強化版です。

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

単にopen locationで電話番号を呼び出しただけでは、通知センターが表示するウィンドウ上の「発信」ボタンをクリックする必要がありました。それを野蛮なGUI ScriptingやCocoaの怪しい機能を活用して、「発信」ボタンをクリックさせることで自動発信を行わせるものです。

本来なら、「発信」ボタンに対してクリックイベントを送ることになりますが、この「発信」ボタンはどうもUI Element Inspectorで調べてもボタンとして認識されなかったため、ウィンドウの位置とサイズの情報だけ取得して、座標を計算してマウスカーソルを強制移動させ、強制的にクリックさせています。そのため、ユーザーがマウスカーソルを動かしている状態だとクリックできない可能性があります。

座標値の計算結果の照合のため、MacBook Pro Retina Mid 2012(Retina解像度)と、MacBook Air Mid 2011で動作確認を行ってあります。もっと遅いマシンで実行する場合には、冒頭のdelayの秒数を増やすなどして調整してください。

tel1.png
▲open locationの実行直後

tel21.png
▲2秒待ったあと、AppleScriptで「発信」ボタンをクリック。本当に発信されている(この電話番号はたぶん実在しないため、スクリーンショットを撮ったあとで慌てて止めています)

AppleScript名:電話番号を呼び出すv2
– Created 2016-04-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ApplicationServices”
use framework “Quartz”

set telNo to “0312345678″ –only numeric characters

open location “tel://” & telNo
delay 2

activate application “NotificationCenter”
tell application “System Events”
  tell process “通知センター” –This name is localized (Japanese)
    set wCount to count every window
    
if wCount is not equal to 1 then return –ウィンドウが表示されていなかった、あるいは多数のウィンドウが表示されていた
    
    
tell window 1
      set {xPos, yPos} to position
      
set {xSize, ySize} to size
    end tell
    
  end tell
end tell

clickAt(xPos + xSize - 20, yPos + 20) of me

–マウスカーソルの強制移動とクリック
on clickAt(newX, newY)
  set pt to current application’s CGPointZero
  
set x of pt to newX
  
set y of pt to newY
  
current application’s CGPostMouseEvent(pt, 1, 1, 1)
  
current application’s CGPostMouseEvent(pt, 1, 1, 0)
end clickAt

★Click Here to Open This Script 

2016/04/27 AppleScriptから電話にアクセスする

指定番号に電話をかけたり、指定番号にSMSのメッセージを投げるAppleScriptです。

OS X 10.10, Yosemiteから、MacとiPhoneをひもづけておくとMacで電話を受けたり、Macから電話をかけたりできるようになりました。

→ OS X Yosemite: Mac を使って電話を受ける/かける

この設定が済んでいれば、以下のような簡単なAppleScriptを実行するだけで、電話がかけられます。ノーティフィケーション・ダイアログが表示されるため、「発信」ボタンをクリックすれば(このあたり、GUI Scriptingでクリックできそう)、電話が発信されます。

プログラム中の「tel://」以下の部分に実際の電話番号を入れておけばかけられます(カッコ、ハイフンなどは入れず、数字のみ)。

phonecall.png

AppleScript名:電話番号を呼び出す
open location “tel://03XXXXXXXX”

★Click Here to Open This Script 

同様に、携帯電話のSMSサービス経由でメッセージを送ることもできます。以下のプログラムのbuddyのあとに電話番号を入れておくとメッセージ送信できます(カッコ、ハイフンなどは入れず、数字のみ)。

以前は、SMS Macという有償のアプリケーションを使う必要があったのですが、OS標準でこの機能がサポートされていることに驚かされました。

iCloud経由のメール送信は1日に200件までという上限が設定されており、このSMS経由のメッセージ送信にも同様の上限値が設定されている可能性があります。

→ iCloud におけるメールボックスの容量およびメッセージの送信制限

img_3554.jpg

img_3556.jpg
▲ためしにAppleScriptから3秒間隔で210回SMS送信実験してみましたが、200回目で止まるようなことはありませんでした

→ キャリア(ソフトバンク)側で、SMSを200通/日以上送信した場合に、その後24時間送信規制を行うとのこと。明日はSMS送信が行えない模様

AppleScript名:携帯電話にSMS経由でメッセージを送信する
tell application “Messages”
  set target to buddy “080XXXXXXXX” of service “SMS”
  
send “SMS sent via AppleScript” to target
end tell

★Click Here to Open This Script 

2016/04/19 URLとrecordからパラメータつきURLを生成する

URL文字列とrecordから、パラメータつきURLを生成するAppleScriptです。

 URL: https://slack.com/api/auth.test
 record: {token:”aaaa”, channel:”applescript”}

のようなURLとrecordを与えたときに、

https://slack.com/api/auth.test?token=aaaa&channel=applescript

のようにパラメータ付きURLに展開するものです。文字列としてゴリゴリ処理すればいいような気もしないでもないですが、将来的に何かいいことがあるかもしれないのでOSの機能を使ってみることにしました。

さまざまなWeb APIを呼ぶ際に、

 「HTTP Headerにパラメータを入れる」
 「HTTP Bodyにパラメータを入れる」(画像認識系とかDropboxとか)
 「URLにパラメータを入れる」

といったパターンがあり、とくに統一されているわけでもないため、別の新たなWebサービスを呼ぼうとしたときに、まいどまいど試行錯誤が必要なのがなかなか大変です。

AppleScript名:URLとrecordからパラメータつきURLを生成する
– Created 2016-04-19 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aBaseURL to “https://slack.com/api/auth.test”
set aRec to {token:“aaaa”, channel:“applescript”}
set aRes to retURLwithParams(aBaseURL, aRec) of me
–>  ”https://slack.com/api/auth.test?token=aaaa&channel=applescript”

on retURLwithParams(aBaseURL, aRec)
  
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
set bLen to length of aValList
  
if aLen is not equal to bLen then return false
  
  set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  return aURL
end retURLwithParams

★Click Here to Open This Script 

2016/04/19 Multi Page Tiffを読み込んで、PDFに変換する

Multipage Tiffを読み込んで、PDFに書き出すAppleScriptです。

意外とサンプルもなく、さまざまなObjective-Cのサンプルの断片をかき集めて、ようやくできました。着手してから1年ぐらい放置してあったぐらいです。

Multipage Tiffのサンプルをここから入手し、試行錯誤してようやく変換できました。

multipage1.png

大昔から存在しているものの、ずーーっとマイナーな存在だったMultipage Tiffなので、こんなもん書いて有用性がどーのとかいうことは一切ないわけですが、1年間放置しておいた未解決の問題を解決できてスッキリしました。

AppleScript名:multi page tiffを読み込んで、PDFにする
– Created 2015-01-01 by Takaaki Naganoya
– Modified 2016-04-18 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “QuartzCore”
use framework “Quartz”
use framework “AppKit”

set a to choose file of type {“public.tiff”} with prompt “Select Multi-page tiff file” –tiff

–Make Output Path
set b to POSIX path of a
set bb to changeExtensionInPath(“pdf”, b) –OutPath

–Read Multi-Page TIFF
set aURL to current application’s |NSURL|’s fileURLWithPath:b
set aImage to current application’s NSImage’s alloc()’s initWithContentsOfURL:aURL
set aRawimg to aImage’s TIFFRepresentation()
set eachTiffPages to (current application’s NSBitmapImageRep’s imageRepsWithData:aRawimg) as list

–Make Blank PDF
set aPDFdoc to current application’s PDFDocument’s alloc()’s init()

set pageNum to 0

repeat with curPage in eachTiffPages
  set thisImage to contents of curPage
  
set aImg to (current application’s NSImage’s alloc()’s initWithSize:(thisImage’s |size|()))
  (
aImg’s addRepresentation:thisImage)
  (
aPDFdoc’s insertPage:(current application’s PDFPage’s alloc()’s initWithImage:aImg) atIndex:pageNum)
  
set pageNum to pageNum + 1
end repeat

aPDFdoc’s writeToFile:bb

–ファイルパス(POSIX path)に対して、拡張子のみ付け替える
on changeExtensionInPath(extStr as string, aPath as string)
  set pathString to current application’s NSString’s stringWithString:aPath
  
set theExtension to pathString’s pathExtension()
  
set thePathNoExt to pathString’s stringByDeletingPathExtension()
  
set newPath to thePathNoExt’s stringByAppendingPathExtension:extStr
  
return newPath as string
end changeExtensionInPath

★Click Here to Open This Script 

2016/04/15 NSURLComponentsのqueryItemsにアクセス

昨日の、

>パラメータが複数用意されている際の処理なども試しておきたいところです。

という件について調査し、複数のクエリーアイテムを取得するAppleScriptを書いてみました。

書いたというよりも、Objective-C版のサンプルをAppleScriptに翻訳しただけなので、ほとんど頭を使わない内容であり、これをプログラミングと呼んではいけないような(ーー;;

AppleScript名:NSURLComponentsのqueryItemsにアクセス
– Created 2016-04-15 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aURLstr to current application’s NSString’s stringWithString:“http://www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf” –複数のクエリーアイテムを含むURL

set components to current application’s NSURLComponents’s alloc()’s initWithString:aURLstr
set qList to (components’s queryItems()) as list
–>  {(NSURLQueryItem) {name = id, value = 340289}, (NSURLQueryItem) {name = name, value = file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf}}

repeat with i in qList
  set aLabel to (i’s |name|()) as string
  
log aLabel
  
–> “id”
  
–> “name”
  
set aVal to (i’s value()) as string
  
log aVal
  
–> “340289″
  
–> “file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”
end repeat

★Click Here to Open This Script 

AppleScript名:NSURLComponentsのqueryItemsでURLを組み立てる
– Created 2016-04-15 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aQuery1 to current application’s NSURLQueryItem’s queryItemWithName:“id” value:“340289″
set aQuery2 to current application’s NSURLQueryItem’s queryItemWithName:“name” value:“file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”

set aComp to current application’s NSURLComponents’s alloc()’s initWithString:“http://www.mhlw.go.jp/file.jsp” –base URL

aComp’s setQueryItems:{aQuery1, aQuery2}
set aURL to (aComp’s |URL|()’s absoluteString()) as text
–>  ”http://www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”

★Click Here to Open This Script 

2016/04/14 NSURLのURLの各要素にアクセスするじっけん

URLの各要素にアクセスするAppleScriptです。

何か、文字列として処理すればいいような気もするのですが、せっかくOSに機能が用意されているので使ってみましょう。

NSURLにいったん変換すれば、さまざまな要素に簡単にアクセスできます。とりあえず各要素を取り出すテストを行い、Dropboxの共有URLについているパラメータ「dl=0」(URLにアクセスするとフォルダが表示される)から「dl=1」(アクセスするとフォルダ内のファイルが直接ダウンロードされる)に変更してみました。

パラメータが複数用意されている際の処理なども試しておきたいところです。

AppleScript名:NSURLのURLの各要素にアクセスするじっけん
– Created 2016-04-03 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aURL to current application’s |NSURL|’s URLWithString:“http://www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”

aURL’s |scheme|()
–>  (NSString) “http”

aURL’s |host|()
–>  (NSString) “www.mhlw.go.jp”

aURL’s absoluteString()
–>  (NSString) “http://www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”

aURL’s |absoluteURL|()
–>  (NSURL) http://www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf

aURL’s baseURL()
–>  missing value

aURL’s fragment()
–>  missing value

aURL’s |lastPathComponent|()
–>  (NSString) “file.jsp”

aURL’s parameterString()
–>  missing value

aURL’s |password|()
–>  missing value

aURL’s |path|()
–>  (NSString) “/file.jsp”

aURL’s pathComponents()
–>  (NSArray) {”/”, “file.jsp”}

aURL’s pathExtension()
–>  (NSString) “jsp”

aURL’s |port|()
–>  missing value

aURL’s query()
–>  (NSString) “id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”

aURL’s relativePath()
–>  (NSString) “/file.jsp”

aURL’s relativeString()
–>  (NSString) “http://www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”

aURL’s resourceSpecifier()
–>  (NSString) “//www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf”

aURL’s standardizedURL()
–>  (NSURL) http://www.mhlw.go.jp/file.jsp?id=340289&name=file/06-Seisakujouhou-12400000-Hokenkyoku/0000117683.pdf

aURL’s user()
–>  missing value

★Click Here to Open This Script 

AppleScript名:Dropboxの共有URLのパラメータを変更する
– Created 2016-04-14 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–Dropbox Sharing URL
set aURLstr to current application’s NSString’s stringWithString:“https://www.dropbox.com/sh/qgqe3glxwx76ava/AAAr7SR_38JL5Xv7t9_DD2i4a?dl=0″
set components to current application’s NSURLComponents’s alloc()’s initWithString:aURLstr
components’s query()
–>  (NSString) “dl=0″

components’s setQuery:“dl=1″
set resURLstr to (components’s |URL|()’s absoluteString()) as text
–>  ”https://www.dropbox.com/sh/qgqe3glxwx76ava/AAAr7SR_38JL5Xv7t9_DD2i4a?dl=1″

★Click Here to Open This Script 

2016/04/13 ISO8601日付文字列を生成

NSDateからISO8601日付文字列を生成するAppleScriptです。

昨日のGHKitによるISO8601日付文字列ではいまひとつDropbox側と仕様が合わず、ちょっと困ってしまいました。

いくつものXcode Projectをgithub上で探してビルドしては捨て、捨ててはビルドしての繰り返しをしていました。ソースが古いとARC対応していなかったりして、かなり書き換える必要が生じてしまいます。

が、そもそも別にそんなたいしたものでもないので(^ー^;; 「自分で書いた方が簡単なんじゃないの?」と気付き、さらっと書きました。

これで、REST API経由でAppleScriptからDropboxを小突きまわして、ファイル共有期限の日時指定を行えます。

AppleScript名:ISO8601日付文字列を生成
– Created 2016-04-13 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use BridgePlust : script “BridgePlus” –for OS X 10.10.x

set aDate to (current date) + 3 * days
set bDate to Cocoaify aDate
set bStr to retISO8601DateTimeString(aDate) as string
–> “2016-04-16T09:23:11Z”

–NSDate -> ISO8601 Date & Time String for Dropbox
on retISO8601DateTimeString(targDate)
  set theNSDateFormatter to current application’s NSDateFormatter’s alloc()’s init()
  
theNSDateFormatter’s setDateFormat:“yyyy-MM-dd’T’HH:mm:ss’Z’”
  
theNSDateFormatter’s setTimeZone:(current application’s NSTimeZone’s alloc()’s initWithName:“UTC”)
  
return (theNSDateFormatter’s stringFromDate:targDate) as text
end retISO8601DateTimeString

★Click Here to Open This Script 

2016/04/12 GHKitで日付フォーマット変換

Gabriel Handford氏によるオープンソースのフレームワーク「GHkit」を利用して、さまざまなフォーマットの日付表現のNSDateとの相互変換(decode/encode)を行うAppleScriptです。

REST経由でさまざまなサービスを呼び出して使っていると、さまざまな形式のタイムスタンプの文字列を扱い、parseする必要に迫られるため、こういう種類のフレームワークがあるのではないかと考えて探したところ見つけました。

オリジナルでは、GHKitの各メソッド名が「gh_」という形式になっており、これ(アンダースコア)がAppleScriptにおけるObjective-Cのメソッド名変換時に問題になったため、Xcode上で自分ですべてリネームして使っています(汗)。

なお、OS X 10.10以降用にビルドしたFrameworkのバイナリを用意しましたので、使ってみたい方はアーカイブを展開したあと~/Library/Frameworksに入れてご利用ください(自己責任で)。

–> Download Framework Binary

AppleScript名:GHKitで日付フォーマット変換
– Created 2016-04-12 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “GHKit” –https://github.com/gabriel/GHKit

– AppleScriptObjC uses “_” as special character (equivalent to “:” in method names). So, I changed them in whole project.
–  Original Method Name: gh_parseISO8601:
–  Converted Method Name: GHparseISO8601:

–Decode RFC822, ISO8601& HTTP format date strings

set aStr to current application’s NSString’s stringWithString:“Sun, 06 Nov 1994 08:49:37 +0000″
set aDate to current application’s NSDate’s GHparseRFC822:aStr
–>  (NSDate) 1994-11-06 08:49:37 +0000

set bStr to current application’s NSString’s stringWithString:“1997-07-16T19:20:30.045Z” –For Dropbox file/folder sharing expiration format
set bDate to current application’s NSDate’s GHparseISO8601:bStr
–>  (NSDate) 1997-07-16 19:20:30 +0000

set cStr to current application’s NSString’s stringWithString:“Tue, 12 Apr 2016 06:28:45 GMT” –Dropbox REST Result header timestamp format
set cDate to current application’s NSDate’s GHparseHTTP:cStr
–>  (NSDate) 2016-04-12 06:28:45 +0000

–Encode NSDate to RFC822, ISO8601& HTTP format date strings

set eDateStr to bDate’s GHformatHTTP()
–>  (NSString) “Wed, 16 Jul 1997 19:20:30 GMT” –For Dropbox file/folder sharing expiration format

set fDateStr to bDate’s GHformatRFC822()
–>  (NSString) “Wed, 16 Jul 1997 19:20:30 +0000″

set gDateStr to bDate’s GHformatISO8601()
–>  (NSString) “1997-07-17T04:20:30.045+09:00″

★Click Here to Open This Script 

2016/04/07 Scripting Bridge経由でアプリケーションを操作

通常のAppleScriptによるアプリケーションのコントロールのほかに、Scripting Bridge経由でアプリケーションにアクセスが可能です。

そこで、AppleScriptからScripting Bridge経由でアプリケーションを操作して、メリットがあるかどうか確認してみることにしました。

同じ内容を5回実行して平均時間をとると、Scripting Bridge経由でアクセスを行うと通常のAppleScriptの2.5倍遅いという結果が出ました。何事も実験が大事なので、一度このように実験しておけば、間違ってもScripting Bridge経由で操作しようとは思わないことでしょう。

compare.png

bridge.png

AppleScript名:普通にiTunesで選択中のトラック情報にアクセス
– Created 2016-04-07 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

tell application “iTunes”
  set aSel to current track
  
properties of aSel
  
–>  {id:40845, index:4, name:”エリザベス はじめてのおつかい”, persistent ID:”80F94D62BDF434F7″, database ID:21177, date added:date “2016年3月10日木曜日 14:28:11″, time:”3:35″, duration:215.052993774414, artist:”銀魂”, album artist:”銀魂”, composer:”Audio Highs”, album:”銀魂 オリジナル・サウンドトラック 4″, genre:”アニメ”, bit rate:256, sample rate:44100, track count:32, track number:2, disc count:1, disc number:1, size:7484506, volume adjustment:0, year:2012, comment:”(エリザベスハジメテノオツカイ)”, EQ:”", kind:”購入した AAC オーディオファイル”, video kind:none, modification date:date “2016年3月10日木曜日 14:28:33″, enabled:true, start:0.0, finish:215.052993774414, played count:12, played date:date “2016年3月28日月曜日 18:13:37″, skipped count:3, skipped date:date “2016年3月28日月曜日 15:57:23″, compilation:false, gapless:missing value, rating:100, bpm:0, grouping:”", podcast:false, iTunesU:false, bookmarkable:false, bookmark:0.0, shufflable:true, lyrics:”", category:”", description:”", long description:missing value, show:”", season number:0, episode ID:”", episode number:0, unplayed:false, sort name:”えりざべすはじめてのおつかい”, sort album:”ぎんたまおりじなるさうんどとらっくふぉー”, sort artist:”銀魂”, sort composer:”", sort album artist:”", sort show:”", release date:date “2012年3月21日水曜日 16:00:00″, loved:false, album loved:false}
end tell

★Click Here to Open This Script 

AppleScript名:Scripting Bridge経由でiTunesの選択中のトラック情報にアクセス
– Created 2016-04-07 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ScriptingBridge”

set iTunes to current application’s SBApplication’s applicationWithBundleIdentifier:“com.apple.iTunes”
if iTunes’s isRunning() then
  set aSel to iTunes’s |currentTrack|()
  
aSel’s |properties|()
  
–>  (NSDictionary) {bitRate:256, year:2012, artist:”銀魂”, dateAdded:(NSDate) 2016-03-10 05:28:11 +0000, videoKind:(AppleScript) «constant ****kNon», objectClass:(AppleScript) «class cFlT», id:40845, albumArtist:”銀魂”, EQ:”", playedCount:12, sortAlbumArtist:”", genre:”アニメ”, discCount:1, releaseDate:(NSDate) 2012-03-21 07:00:00 +0000, rating:100, bookmarkable:0, show:”", episodeID:”", trackNumber:2, longDescription:missing value, album:”銀魂 オリジナル・サウンドトラック 4″, sortComposer:”", playedDate:(NSDate) 2016-03-28 09:13:37 +0000, bookmark:0.0, episodeNumber:0, size:7484506, iTunesU:0, start:0.0, sortArtist:”銀魂”, discNumber:1, skippedDate:(NSDate) 2016-03-28 06:57:23 +0000, gapless:missing value, objectDescription:”", name:”エリザベス はじめてのおつかい”, comment:”(エリザベスハジメテノオツカイ)”, compilation:0, sortName:”えりざべすはじめてのおつかい”, shufflable:1, lyrics:”", kind:”購入した AAC オーディオファイル”, trackCount:32, composer:”Audio Highs”, category:”", podcast:0, duration:215.052993774414, sampleRate:44100, finish:215.052993774414, grouping:”", unplayed:0, albumLoved:0, sortShow:”", bpm:0, seasonNumber:0, sortAlbum:”ぎんたまおりじなるさうんどとらっくふぉー”, index:4, time:”3:35″, loved:0, modificationDate:(NSDate) 2016-03-10 05:28:33 +0000, databaseID:21177, skippedCount:3, persistentID:”80F94D62BDF434F7″, volumeAdjustment:0, enabled:1}
end if

★Click Here to Open This Script 

2016/04/06 指定のDiskの情報を取得する

diskutilコマンドの結果をparseして、指定のデバイス名のdiskの情報を取得するAppleScriptです。

デバイス名はbsdレイヤーで利用している/dev/xxxxxといった名前であり、マウント中の光学メディア(CD-R、DVD-R、BD-Rなど)のbsdデバイス名を求めるのはちょっと手間がかかります。本来なら、choose folderコマンドで指定したドライブ(に含まれているフォルダ)からbsdデバイス名を求めて処理・・・をしたかったのですが、時間がなかったのでとりあえず決め打ちで。

とりあえず、指定のドライブに入っている光学メディアの種類(Optical Media Type)と、光学ドライブ側がサポートしているメディアの種類(Optical Drive Type)を取得できます。結果がNSDictionaryになっているため、Script Editor上では内容を確認できません。AppleScriptネイティブのrecord型のデータだと属性ラベルの自由度が低いため(属性ラベルに空白文字とか入りませんし)、NSDictionaryのままにしてあります。

AppleScript名:指定のDiskの情報を取得する
– Created 2016-04-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set targDev to “/dev/disk3″ –Blu-ray drive via USB

set aDict to current application’s NSMutableDictionary’s alloc()’s init()
set a to do shell script “diskutil info “ & targDev
set aList to paragraphs of a

repeat with i in aList
  set j to contents of i
  
if j is not equal to “” then
    set jj to parseByDelim(j, “:”) of me
    
    
if (count every item of jj) is equal to 2 then
      copy jj to {j2, j3}
      
      
set jj2 to (current application’s NSString’s stringWithString:j2)
      
set jj3 to (current application’s NSString’s stringWithString:j3)
      
      
set jjj2 to (jj2’s stringByTrimmingCharactersInSet:(current application’s NSCharacterSet’s whitespaceCharacterSet()))
      
set jjj3 to (jj3’s stringByTrimmingCharactersInSet:(current application’s NSCharacterSet’s whitespaceCharacterSet()))
      
      (
aDict’s setValue:jjj3 forKey:jjj2)
    end if
    
  end if
end repeat

return aDict
–>  (NSDictionary) {Read-Only Media:”Yes”, OS Can Be Installed:”No”, Volume Name:”Not applicable (no file system)”, OS 9 Drivers:”No”, Virtual:”No”, Device Block Size:”2048 Bytes”, Low Level Format:”Not supported”, Removable Media:”Yes”, Device / Media Name:”MATSHITA BD-MLT UJ240AS”, Optical Media Erasable:”No”, Optical Drive Type:”CD-ROM, CD-R, CD-RW, DVD-ROM, DVD-R, DVD-R DL, DVD-RW, DVD-RAM, DVD+R, DVD+R DL, DVD+RW, BD-ROM, BD-R, BD-RE”, Part of Whole:”disk3″, Device Identifier:”disk3″, Whole:”Yes”, Optical Media Type:”BD-R”, SMART Status:”Not Supported”, Device Location:”External”, Volume Free Space:”Not applicable (no file system)”, Device Node:”/dev/disk3″, Read-Only Volume:”Not applicable (no file system)”, Media Type:”Generic”, Total Size:”0 B (0 Bytes) (exactly 0 512-Byte-Units)”, Media Removal:”Software-Activated”, Mounted:”Not applicable (no file system)”, Content (IOContent):”None”, File System:”None”, Protocol:”USB”}

–テキストを指定デリミタでリスト化
on parseByDelim(aData, aDelim)
  set aText to current application’s NSString’s stringWithString:aData
  
set aList to aText’s componentsSeparatedByString:aDelim
  
return aList as list
end parseByDelim

★Click Here to Open This Script 

2016/04/05 質問を募集します

6/25(土)に秋葉原で開催される「技術書典」に申し込み、そこで販売するAppleScript入門書の内容を検討中です。

入門書の媒体はDVDです。内容は、解説HTML+ムービー+Script Editorアシスタント(Script Editorのコンテクストメニューから呼び出してAppleScriptを入力する、生産性を大幅に向上させるAppleScript)。

紙でも検討したものの、決まってからイベントまでの時間がなさすぎるのと、カラー印刷すると(カラーでないAppleScript入門書は地獄なので)コストがかかりすぎて大変なため見送りました。紙で作っても、どうせオマケDVDが必要になってしまうので。

# 当日も、ブースで店番しながらDVDを焼くことになるはずなので、DVD作成用のAppleScriptを書いておいて、DVDメディアを入れると自動で焼いてイジェクトするようにしておくべき>自分

4月末に当落が判明しますが、会場(通運会館)のデータから察するに、およそ30サークル前後が参加できるようになっているようです。

しかし、Q&Aのコーナーになかなかいい質問が揃いません。あまり大きくない内容の質問であれば、AppleScript入門書に掲載しますので、入門者レベルの質問を募集いたします。質問のあるかたは、maro@piyocast.comまで「入門書用の質問です」というサブジェクトで質問を投げてみてください。なお、メールによる回答は期待しないでください。

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 

2016/04/02 Contactsに登録してある自分の写真をPNGでデスクトップに保存する

Contacts.app(旧称:アドレスブック)に登録してある自分の写真をデスクトップにPNG形式で保存するAppleScriptです。

AppleScript名:Contactsに登録してある自分の写真をPNGでデスクトップに保存する
– Created 2016-04-02 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AddressBook”

set imgData to current application’s ABAddressBook’s sharedAddressBook()’s |me|()’s imageData()

set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.png”)

saveTIFFDataAtPathAsPNG(imgData, savePath) of me

–NSImageを指定パスにPNG形式で保存
on saveTIFFDataAtPathAsPNG(anImage, outPath)
  –set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:anImage
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –成功ならtrue、失敗ならfalseが返る
end saveTIFFDataAtPathAsPNG

★Click Here to Open This Script