Archive for 1月, 2017

2017/01/31 US Appleの各種MLが先週末からダウン

US Appleが主催している開発系(&営業系、ユーザー系&政府官公庁系+学校系)メーリングリスト(以下、ML)が、先週末からダウンしておりました。

同サイトに記載のあるpostmasterのアドレスあてに確認のメールを出すも応答がなく、Webサーバー(http://lists.apple.com)は反応するもののMLサーバーかメールサーバーが単独で落ちているような雰囲気。

AppleのMLサーバー運用は社内的にほぼ放置状態のようで、数年に一度クラッシュしては復旧を繰り返してきました。10年ぐらい前にいちどハードウェアごとクラッシュしてサーバーごと入れ替えたことを記憶しています。

AppleScript Users MLは1999年ごろからのログが残っており、18年ぐらい続いている計算になります(それ以前のものはメール送信側のシステム日付の設定ミスだかなんだかでその日付になっていますが実際には異なるようです)。

そんなMLサーバーの復旧について、postmasterにメールで確認しても返答がないので、CEO宛てに直接「なんとかしてー」とメール。

本人が読むことはなくても、CEO直轄部隊が手分けをしてメールの処理をしていることは周知の事実です。さきほど、メールの返事が来ると同時に遅配通知メールが届き、復旧に向けて動き出したことが感じられます(ただし、そこからが大変)。

外部からの攻撃を受けてダウンしていたような場合にはどーなのか。その後の展開が待たれるところです。

Apple系の開発者コミュニティには、大きく分けるとWeb上の開発者専用フォーラム(Developper契約者のみ利用可)と、誰でも入れるMLがあります(政府系や官公庁系、学校系のMLからは追い出されました)。自分は入れるMLにはすべて入っており、その数108ほど。それぞれのMLのログを手元でAppleScriptロボットによって自動で整理・分類しています。

数年前に「Apple社員はフォーラムに投稿しろ」といった社内通達があったためか(憶測)、メーリングリスト側にApple社員が投稿する量は大幅に減っています(といっても、フォーラム側に投稿しているようにも見えない)。

ただし、AppleScript系についてはApple社員とはほぼ関係のない独自の情報生態系が維持されており、社員が出てこなくてもほぼ関係ありません。

フォーラム自体ものぞいていますが使い勝手がいまひとつで、継続的に情報を蓄積していくことを考えるとMLに分があるように感じています(個人的な意見です)。

そんなわけで、メーリングリストがコケていると本当に困るのです。無事再稼働できるよう、祈るばかりです。

2017/01/31 DragThing上で選択中のSlotのアイコン画像をデスクトップに書き出す

DragThing上で選択中のSlotのアイコン画像をデスクトップに書き出すAppleScriptです。

ランチャーの老舗、James ThomasonのDragThing(バージョン5.9.17)を愛用しています。macOS標準搭載のDockには最小限のアプリケーションのみ登録しておき、基本的にはDragThingから起動。

dt0.png

dt1.png

さまざまなアプリケーションの紹介を行うKeynote書類を作るために、Finder上で選択しておいたアプリケーションのアイコン画像を書き出すAppleScriptは作ってありました。

dt00_resized.png

その一方で、DragThing上の選択中のアプリケーションのアイコンを書き出すようなものはなかったので、DragThing上で選択→Finderに表示→アイコン書き出しScript実行 と操作していたのですが、あまりに不毛なのでDragThing上から直接書き出せるものを作ってみました。

Dockに大量のアプリケーションを登録し、1個1個が豆粒大になっているユーザーを見かけますが、大量のアプリケーションを登録・管理するのであれば、タブでジャンル分けして管理できるDragThingのほうがおすすめです。

また、DragThingはURLも登録しておけます。DragThingをブックマークとして利用することで、Webブラウザの共通ブックマークとして運用できるため、日常的に複数のWebブラウザを利用している人にとってはたいへん便利でしょう。

dt2_resized.png

dt3.png

macOS標準装備のScript Menuに登録して呼び出しています。

dt4_resized.png

AppleScript名:DragThing上で選択中のSlotのアイコンをデスクトップに書き出し v2
– Created 2017-01-31 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4419

tell application “DragThing”
  –Version 5.9.17で動作確認
  
set aSel to selection
  
if aSel = {} then return
  
  
set bSelected to {}
  
repeat with i in aSel
    set j to contents of i
    
try
      –ここでエラーが出ないということは、Dockに登録したファイルである(URLではない)と仮定
      
set aPath to file location of j
      
      
—選択したSlotの内容がアプリケーションだったらデスクトップにアイコン画像を書き出す
      
set fRes to detectAppFile(aPath) of me
      
if fRes = true then
        writeOutICNS(aPath) of me
      end if
    end try
  end repeat
  
end tell

on detectAppFile(aPath)
  tell application “System Events”
    set fType to file type of aPath
    
return (fType as string = “APPL”)
  end tell
end detectAppFile

–指定ファイルのアイコンをCFBundleIdentifierの名称でtmpにPNGで書き出す
on writeOutICNS(aFile)
  set aPOSIXpath to POSIX path of aFile
  
set anURL to current application’s |NSURL|’s fileURLWithPath:aPOSIXpath
  
  
set myBundle to current application’s NSBundle’s bundleWithURL:anURL
  
set aBundleID to myBundle’s bundleIdentifier() as text
  
set anIconFileName to (myBundle’s objectForInfoDictionaryKey:“CFBundleIconFile”) as string
  
  
–アイコン名には拡張子を省略してもよいので、ない場合には補う
  
if anIconFileName does not end with “.icns” then
    set anIconFileName to anIconFileName & “.icns”
  end if
  
  
set ifonFileFullPath to aPOSIXpath & “Contents/Resources/” & anIconFileName
  
  
set sText to “cp “ & quoted form of ifonFileFullPath & ” ~/Desktop/” & quoted form of (aBundleID & “.icns”)
  
do shell script sText
  
end writeOutICNS

★Click Here to Open This Script 

2017/01/30 Cocoa勉強会松戸で発表した内容を公開

2017/1/28に松戸で行われた「Cocoa勉強会松戸」でPiyomaru Softwareが発表した内容をSlide Shareで公開しました。

→ SlideShare Link

「”アイデアを練る”ソフトウェアとは?」と題し、アイデアを考えるプロセスそのものを分析。アイデア作成過程で行うさまざまな作業に、既存のソフトウェアがどのように役立ち、どのように役に立っていないのか、、、、また、新たに登場してきた技術によってどのように補完していけるのかを発表しました。

Cocoa勉強会「松戸」と聞くと、東京界隈(23区近辺)からはずいぶんと遠い印象を受けますが・・・ウチの最寄駅である西武池袋線「中村橋」駅からだと、中村橋→池袋→日暮里→松戸 でトータル45分(最短で、だいたい50分から1時間)。実はそれほど遠くありません。

Cocoa勉強会「池袋」「松戸」、「MOSA自習室(池袋)」など、Cocoa開発者向けのイベントがだいたい1週間に一度あるので、いろいろと刺激&勉強になります。

Cocoa APIへの理解や情報交換を目的とした集まりなので、発表もObjective-C、Swift、AppleScriptなどプログラミング言語のバラエティーに富んでいます。

2017/01/30 2つのパスの相対パスを求める v2

2つのPOSIX pathの相対位置を求めるAppleScriptです。aFileの位置から見た、bFileの相対パス表記を求めます。

→ 改修版(v3)をご覧ください

オリジナル版に対してShane Stanleyからのツッコミが入り、「こういう風にも書けるぞ」というpathComponentsを使ったバージョンを送ってもらいました。

自分もpathComponentsによる分解はちょっと考えてみたものの、分解したあとの戻し方(結合方法)がわからなかったので、手軽な方法(デリミタによる分解、デリミタを指定しての結合)に落ち着いたという経緯があります。

pathWithComponentsでこんな風にパスをつなげるのは知らなかった、、、、(^ー^;

ちなみに、本バージョンはオリジナル版にくらべて20%ぐらい高速なようです(1,000回実行時の平均)。

relativepath_resized.png

AppleScript実行速度計測ソフト「Script Geek」の実行結果。同一の処理を行う複数のAppleScriptの処理速度比較を客観的に行える

AppleScript名:2つのパスの相対パスを求める v2
– Created 2017-01-28 by Takaaki Naganoya
– Modified 2017-01-30 by Shane Stanley
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4416

set aFile to “/Users/me/Documents/Book1/0900 Command Reference/1000 Command References/1010 tell/1010 tell.md”
set bFile to “/Users/me/Documents/Book1/9999_images/002-640×427.png”

set relativePath to calcRelativePath(aFile, bFile) of me
–>  ”……/9999_images/002-640×427.png”

on calcRelativePath(aPOSIXfile, bPOSIXfile)
  set aStr to current application’s NSString’s stringWithString:aPOSIXfile
  
set bStr to current application’s NSString’s stringWithString:bPOSIXfile
  
  
set aList to aStr’s pathComponents() as list
  
set bList to bStr’s pathComponents() as list
  
  
set aLen to length of aList
  
set bLen to length of bList
  
  
if aLen bLen then
    copy aLen to aMax
  else
    copy bLen to aMax
  end if
  
  
repeat with i from 1 to aMax
    set aTmp to contents of item i of aList
    
set bTmp to contents of item i of bList
    
    
if aTmp is not equal to bTmp then
      exit repeat
    end if
  end repeat
  
  
set bbList to items i thru -1 of bList
  
set aaItem to (length of aList) - i
  
  
set tmpStr to “”
  
repeat with ii from 1 to aaItem
    set tmpStr to tmpStr & “..”
  end repeat
  
  
set allRes to current application’s NSString’s pathWithComponents:({tmpStr} & bbList)
  
return allRes as text
end calcRelativePath

★Click Here to Open This Script 

2017/01/28 2つのパスの相対パスを求める

2つのPOSIX pathの相対位置を求めるAppleScriptです。aFileの位置から見た、bFileの相対パス表記を求めます。

画像をDropboxにアップロードして、そのリンクをMarkdown書類に記述していました。

実験的な試みであったものの、いちいちWeb上の画像を読みに行くため処理が遅く、決まったマシンでしか作業しないのでクラウドに画像を置いている意味がほとんどありませんでした。

結局、「ローカルに置けばいいじゃないか!」ということに。

指定フォルダ以下のMarkdown書類をSpotlightで抽出し、Markdown書類のテキストエンコーディングを自動判定して本文を抽出、本文中から画像リンクURLを抽出して所定のフォルダに画像をダウンロードするまでは簡単にありもののAppleScriptの組み合わせで書けたものの、問題は画像リンクの書き換え。

あらたにローカルにダウンロードした画像へのリンクを求める際に、MarkDown書類からの相対パスを指定する必要がありました。かるく調べた範囲では、2つのパスの相対パスを求めるmethodやプログラムが見つからなかったので、AppleScriptで書いてみました。

書いたあとで、Objective-Cなど他の言語の実装例もいろいろ見つけましたが、誰がどのような言語処理系で書いてもだいたい同じ処理内容でした。

# 自分が使っているMarkdownエディタである「MacDown」では画像リンク時の相対指定が効かなかったので、本ルーチンはオクラ入りに(^ー^;

AppleScript名:2つのパスの相対パスを求める
– Created 2017-01-28 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4415

set aFile to “/Users/me/Documents/Book1/0900 Command Reference/1000 Command References/1010 tell/1010 tell.md”
set bFile to “/Users/me/Documents/Book1/9999_images/002-640×427.png”

set relativePath to calcRelativePath(aFile, bFile) of me
–>  ”……/9999_images/002-640×427.png”

on calcRelativePath(aPOSIXfile, bPOSIXfile)
  set aStr to text 2 thru -1 of aPOSIXfile
  
set bStr to text 2 thru -1 of bPOSIXfile
  
  
set aList to parseByDelim(aStr, “/”) of me
  
set bList to parseByDelim(bStr, “/”) of me
  
  
set aLen to length of aList
  
set bLen to length of bList
  
  
if aLen bLen then
    copy aLen to aMax
  else
    copy bLen to aMax
  end if
  
  
repeat with i from 1 to aMax
    set aTmp to contents of item i of aList
    
set bTmp to contents of item i of bList
    
    
if aTmp is not equal to bTmp then
      exit repeat
    end if
  end repeat
  
  
set bbList to items i thru -1 of bList
  
set aaItem to (length of aList) - i
  
  
set tmpStr to “”
  
repeat with ii from 1 to aaItem
    set tmpStr to tmpStr & “..”
  end repeat
  
  
set allRes to tmpStr & “/” & retStrFromArrayWithDelimiter(bbList, “/”) of me
  
return allRes
end calcRelativePath

on retStrFromArrayWithDelimiter(aList, aDelim)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retStrFromArrayWithDelimiter

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 

2017/01/27 ASOCの美しい書き方?

AppleScriptからCocoaの機能を呼び出すことができるようになり、AppleScript本来の簡潔な記述はしにくくなりました。

ASOCの記述方法について、どのようなアプローチが可能かをまとめてみました。

(1)は、ふだん書いているやり方です。一番安全で確実にAppleScriptの処理系に解釈されるので、トラブル回避のためにこの書き方をしています。ただし、1行がものすごく長くなるので、本Blogに掲載したときの「見た目」がよろしくありません(エディタの上では問題ないのですが、、、)

(2)は、Xcode上のAppleScriptでよくやる書き方です。インデントを基本としたAppleScriptらしいスタイルにはなっているものの、書かなくてはならない情報が多く、やや面倒と感じます。

(3)は、(2)でインデントの段数の増えすぎたことに対する改良とでも呼ぶべきものでしょうか。「its」を毎回書く必要があることに対し、抵抗感があるかないかが問題でしょう。

(4)は、Script Debugger 6のテンプレートに入っていた記述で、なかなかいい手だと思います(Xcode上でもやっていましたが)。ただ、プログラムが長く複雑になると冒頭のProperty宣言部分がどんどん長くなるという問題もあります。

サンプルとして書くのであれば、(4)あたりを検討すべきなんでしょう。

AppleScript名:(1)quick style
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4412

set a to (current application’s NSString’s stringWithString:“aaaaa”) as string
–>  ”aaaaa”

★Click Here to Open This Script 

AppleScript名:(2)xcode style
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4412

tell current application
  tell class “NSString”
    set a to (its stringWithString:“aaaaa”) as string
  end tell
end tell
–>  ”aaaaa”

★Click Here to Open This Script 

AppleScript名:(3)layer style
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4412

tell current application’s NSString
  set a to (its stringWithString:“aaaa”) as string
end tell
–>  ”aaaa”

★Click Here to Open This Script 

AppleScript名:(4)mark alldritt style
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions
–http://piyocast.com/as/archives/4412

property NSString : a reference to current application’s NSString

set a to (NSString’s stringWithString:“aaaa”) as string
–>  ”aaaa”

★Click Here to Open This Script 

実際に(4)のスタイルで書いてみたら、NSMakeRangeやNSMaxRangeなどのObjective-Cのメソッドでない部分を同じスタイルに統一できなくて(current application’sを省略できなくて)、化けきれていない感じが、、、、

あとは、スクリプトエディタ上だとほとんど構文要素の変化に乏しく、メリハリがない(構文要素カラーリングの効果がなく)ので書く方にとって読みにくくなるような気がします。

macOS標準搭載のスクリプトエディタでは、Cocoaのclass名もmethod名も同じ色で表示されてしまいますが、ASObjC Explorer 4やScript Debugger 6ではmethod名を別の色で表示する機能が実装されているため、やはりそうしたツールがないと辛い感じです。

mi.png

AppleScript名:テキストエディタ「mi」で選択中のテキストからHTMLタグを外して逆順に並べなおす
– Created 2017-01-27 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4412

property NSString : a reference to current application’s NSString
property NSAttributedString : a reference to current application’s NSAttributedString
property NSArray : a reference to current application’s NSArray
property NSMutableArray : a reference to current application’s NSMutableArray
property NSUTF16StringEncoding : a reference to current application’s NSUTF16StringEncoding

tell application “mi”
  tell document 1
    set aText to selection
  end tell
end tell

–選択部分のテキストからHTMLのタグを外す
set anNSString to NSString’s stringWithString:aText
set theData to anNSString’s dataUsingEncoding:(NSUTF16StringEncoding)
set styledString to NSAttributedString’s alloc()’s initWithHTML:theData documentAttributes:(missing value)
set plainText to (styledString’s |string|())

–テキストを行ごとにparseしてNSArrayに
set anArray to NSMutableArray’s alloc()’s init()
set aRange to current application’s NSMakeRange(0, plainText’s |length|())

repeat while aRange’s |length|() > 0
  set subRange to plainText’s lineRangeForRange:(current application’s NSMakeRange(aRange’s location(), 0))
  
  
–行が改行コードまで取得されるので、改行コードを除外するように微調整
  
copy subRange to tmpRange
  
set tmpRange’s |length| to ((subRange’s |length|()) - 1) –微調整
  
set aLine to plainText’s substringWithRange:tmpRange
  
anArray’s addObject:aLine
  
  
set aRange’s location to (current application’s NSMaxRange(subRange))
  
set aRange’s |length| to ((aRange’s |length|()) - (subRange’s |length|()))
end repeat

–NSArrayを逆順に(reverse order array)
set outArray to (anArray’s reverseObjectEnumerator())’s allObjects()

–NSArray to string with line delimiter
set outStr to retStrFromArrayWithDelimiter(outArray, return) of me

–リストを指定デリミタをはさんでテキスト化
on retStrFromArrayWithDelimiter(aList, aDelim)
  set anArray to NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as text
end retStrFromArrayWithDelimiter

★Click Here to Open This Script 

2017/01/26 Open Directory経由でアカウント一覧を取得する v1

OpenDirectoryの機能を用いて、Script実行中のマシンのアカウント名一覧を取得するAppleScriptです。

daemon accountの表示を抑止するためにいろいろ試していたものの、まだうまく操作できていません(ーー;

AppleScript名:Open Directory経由でアカウント一覧を取得する v1
– Created 2017-01-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “OpenDirectory”
–http://stackoverflow.com/questions/1303561/list-of-all-users-and-groups
–http://piyocast.com/as/archives/4411

set aSession to current application’s ODSession’s defaultSession()
set aRoot to current application’s ODNode’s nodeWithSession:aSession |name|:“/Local/Default” |error|:(missing value)
if aRoot = missing value then error “ODNode Error”

set aQuery to current application’s ODQuery’s queryWithNode:aRoot forRecordTypes:(current application’s kODRecordTypeUsers) |attribute|:(missing value) matchType:0 queryValues:(missing value) returnAttributes:(missing value) maximumResults:0 |error|:(missing value)
if aQuery = missing value then error “aQuery Error”

set resList to (aQuery’s resultsAllowingPartial:false |error|:(missing value)) as list
repeat with i in resList
  set aRes to (i’s recordName()) as string
  
log aRes
end repeat

★Click Here to Open This Script 

2017/01/25 MediaInfoKitでQuickTimeムービーから詳細な情報を取得する

オープンソースのフレームワーク「MediaInfoKit」(By Jeremy Vizzini)を用いて、指定のムービーや画像から詳細な情報を取得するAppleScriptです。

実行のためにはMediaInfoKit.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

処理結果をScript Editor上でも確認できるように、recordに変換していますが・・・そのままでは属性値ラベルを指定しても値を取り出せないので、実際にはNSDictionaryのままにしておかないと後続の処理ができません。ねんのため。

–English Version

This is a sample AppleScript to call open-source based framework “MediaInfoKit” by Jeremy Vizzini. This script requires macOS 10.10 or greater (I wrote this on macOS 10.12).

To test this AppleScript, at first, you have to build “MediaInfoKit.framework” project with Xcode, then move the framework binary to ~/Library/Frameworks folder.

MediaInfoKit.framework can get movie/picture’s detailed information.

To input this script, your operation is only to click “Click Here to Open This Script” link located the bottom of this AppleScript list bellow. Then the script will be transfered to Script Editor (Web browser may display some warning message, you have to click “OK” button if you believe me :-) .

Apple’s genuine Script Editor can not log the Cocoa-object (NSDictionary) , so this sample returns AppleScript’s record data which can be logged with Script Editor.

But the record’s attribute label can not include “.”, “:” and ” ” characters, so you can not take each values out from this result data (record). If you want to go next step, you have to hold the data as an NSDictionary not record.

AppleScript名:MediaInfoKitでQuickTimeムービーから詳細な情報を取得する
– Created 2017-01-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MediaInfoKit” –https://github.com/jeremyvizzini/MediaInfoKit
–http://piyocast.com/as/archives/4410

set aMovie to POSIX path of (choose file) –(choose file of type {”com.apple.quicktime-movie”})
set aURL to current application’s |NSURL|’s fileURLWithPath:aMovie
set aInfo to current application’s MIKMediaInfo’s alloc()’s initWithFileURL:aURL
set a1info to aInfo’s valuesOfStream:“General”

–Get Each Information
set a2info to aInfo’s valueForKey:“Complete name” ofStream:“General”
–>  (NSString) “/Users/me/Desktop/IMG_0217.MOV”

set a4Info to aInfo’s jsonText() –json形式で取得
–set a5Info to aInfo’s plistText()–plist形式で取得
–set a6Info to aInfo’s csvText()–csv形式で取得
–set a3Info to aInfo’s attributedText()–スタイルつきテキストで取得

—JSON to NSDictionary to record
set jsonData to a4Info’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
set aRec to aJsonDict as record
–Movie file
–>  {General:{Encoded date:”UTC 2017-01-24 04:03:48″, Format profile:”QuickTime”, Overall bit rate mode:”Variable”, Tagged date:”UTC 2017-01-24 04:04:40″, Codec ID:”qt 0000.00 (qt )”, com.apple.quicktime.software:”10.2″, Format:”MPEG-4″, Complete name:”/Users/me/Desktop/IMG_0219.MOV”, Duration:”52 s 53 ms”, File size:”50.8 MiB”, Writing library:”Apple QuickTime”, Overall bit rate:”8 191 kb/s”, com.apple.quicktime.make:”Apple”, com.apple.quicktime.model:”iPhone 7″, com.apple.quicktime.creationdate:”2017-01-24T13:03:47+0900″, com.apple.quicktime.location.ISO6709:”+35.xxxx+139.xxxx+043.xxx/”}, Video:{Minimum frame rate:”28.571 FPS”, Display aspect ratio:”16:9″, Bit depth:”8 bits”, Scan type:”Progressive”, Title:”Core Media Video”, Chroma subsampling:”4:2:0″, Color range:”Limited”, Format/Info:”Advanced Video Codec”, Frame rate:”29.970 (29970/1000) FPS”, Bits/(Pixel*Frame):”0.292″, Frame rate mode:”Variable”, Format:”AVC”, Matrix coefficients:”BT.709″, Encoded date:”UTC 2017-01-24 04:03:48″, Rotation:”90°”, Height:”720 pixels”, Color space:”YUV”, Transfer characteristics:”BT.709″, Duration:”52 s 53 ms”, Bit rate:”8 079 kb/s”, Codec ID:”avc1″, ID:”1″, Width:”1 280 pixels”, Tagged date:”UTC 2017-01-24 04:04:40″, Format profile:”High@L3.1″, Color primaries:”BT.709″, Maximum frame rate:”30.000 FPS”, Stream size:”50.1 MiB (99%)”, Codec ID/Info:”Advanced Video Coding”, Format settings:”CABAC,Yes”}, Audio:{Other:”1″, Title:”Core Media Audio”, Channel(s):”1 channel”, Format/Info:”Advanced Audio Codec”, Frame rate:”43.066 FPS (1024 spf)”, Sampling rate:”44.1 kHz”, Source duration:”52 s 106 ms”, Format:”AAC”, Compression mode:”Lossy”, Encoded date:”UTC 2017-01-24 04:03:48″, Channel positions:”Front: C”, Type:”meta”, Duration:”52 s 53 ms”, Bit rate mode:”Variable”, Source stream size:”568 KiB (1%)”, Bit rate:”89.3 kb/s”, Codec ID:”40″, ID:”2″, Tagged date:”UTC 2017-01-24 04:04:40″, Format profile:”LC”, Stream size:”568 KiB (1%)”}}

–Image file
–>  {General:{Format/Info:”Portable Network Graphic”, Complete name:”/Users/me/Desktop/スクリーンショット 2.png”, File size:”33.3 KiB”, Format:”PNG”}, Image:{Height:”319 pixels”, Format:”PNG”, Bit depth:”32 bits”, Format/Info:”Portable Network Graphic”, Width:”352 pixels”, Compression mode:”Lossless”, Stream size:”33.3 KiB (100%)”}}

★Click Here to Open This Script 

2017/01/24 macOS, SierraでRAMディスクを利用する

以前に掲載したRAMディスク作成Scriptとは若干手順が違うものの、RAM Diskを作成するAppleScriptです。

macOS 10.6のときに作成した「指定容量のRAMディスクを作る」Scriptも、macOS Sierra上で問題なく動きます。

ただし、Finder上のディスク容量の表示基準がかわったのでそのあたりパラメータを変更しつつ、元ネタになっているWeb上の記事ともども紹介しておきます。

参考記事:How to Create a 4GB/s RAM Disk in Mac OS X

RAM Diskのパフォーマンス計測のためには、このジャンルで一番見かける「Blackmagic Disk Speed Test」が使えません。(記事作成時のバージョン3.0では)同ツールは2GB/secが計測上限になっており、それを上回ることが期待されるRAM Diskの計測では正確な数値が計測できないことになります。

そこで、MacBook Pro Retina Late 2016の内蔵SSDのスピード計測に知人が利用していた「AJA System Test Light」を使ってみました。結果は以下のようになりました。

ramdisk_bench.png

何回も計測→アンマウント→再マウント と繰り返してみたものの、いまひとつ数値が安定しない印象があります。「これが計測結果です」と言いにくい雰囲気。

比較のために、同マシンの内蔵SSDのスピード計測結果がこちら(↓)です。

ssd_bench.png

最新のマシンに比べると現在ではそれほど高速ではありませんが、(MBP 2016と比べても)CPUの処理能力自体がそれほど変わっていないので、数値上の差ほど体感速度は変わらない感じがします(もう十分に高速なので)。起動速度の比較なども行いましたが、MBP 2012よりMBP 2016が数秒(ほんのすこし)速いぐらいの差でした。

そうした(最新ではない)マシンでも、高速なストレージを(一時的に)利用できるわけで、古めのマシンを使っているユーザーにとってRAM DISKの併用は悪くない選択肢といえるでしょう。

製品ラインナップのほとんどがSSD搭載機体になっている(iMacとMac miniにはHDD搭載機も残っていますが)昨今、RAMディスクの意義についてはあまり思い至ることがなかったのですが、実際にこうしてパフォーマンスを計測してみると内蔵SSDよりも(MacBook Pro Retina 2012にとっては)高速。一時的な作業場所としてはなかなかいいのかもしれません。

小容量のファイルを大量に作成するような処理を行う場合に、AppleScriptからRAMディスク作成処理を行い、RAMディスク上で処理して結果をHDDやSSDにコピーし、終了後にRAMディスクをアンマウントするようなワークフローもアリだと思います。

AppleScript名:指定容量の指定名称のRAMディスクを作成する
– Created 2017-01-24 by Takaaki Naganoya
– 2017 Piyomaru Software
–https://www.tekrevue.com/tip/how-to-create-a-4gbs-ram-disk-in-mac-os-x/
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4407

set dName to “RAM Disk”
set dCapacity to 2000 * 1000 –1GB
set aCmd to “diskutil erasevolume HFS+ ’” & dName & “’ `hdiutil attach -nomount ram://” & (dCapacity as string) & “`”
try
  do shell script aCmd
end try

★Click Here to Open This Script 

AppleScript名:作成したRAMディスクをイジェクトする
– Created 2017-01-24 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4407

tell application “Finder”
  set tDisk to disk “RAM Disk”
  
eject tDisk
end tell

★Click Here to Open This Script 

2017/01/23 Mail.appで選択中のメッセージからソースを取得してMailCoreで再組み立てして解釈

Mail.appに対してメール(message)の各種属性を問い合わせるのと、Mail.appからメール(message)のソースを取得して、オープンソースのフレームワーク「mailcore2」で各種属性を取得するのとでどちらが速いかを確認するための実験です。

実行のためにはMailCore.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

だいたい同じぐらいの属性値を取り出してみたところ、MacBook Pro Retina 2012モデル(Core i7 2.66GHz)でmailcore2経由の処理のほうが1.8倍ぐらい高速(10回実行時の平均値)なことがわかりました。

漫然とAppleScriptからMailの属性値を取ると0.011秒、mailcore2経由だと0.006秒でした。1通のメールでこのぐらいなので、数十、数百通と処理を行うと差が開く可能性はあります。

ただし、普通にMail.appからメールの属性値を取り出す場合にはpropertiesでまとめて取得するのが賢いやりかたなので、そこまで露骨に処理速度の差は出ないかもしれません。

それでも、mailcore2でしか取得できない情報が割といろいろあるので、mailcore2を使っての処理も悪くない感じです(意外でした)。Mailのメッセージのソースをmailcore2で処理できるかどうかの実験だったのですが、速度もなかなか速かったので速度比較をしてみたものです。

AppleScript名:Mail.appで選択中のメッセージからソースを取得してMailCoreで再組み立てして解釈
– Created 2017-01-23 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MailCore” –https://github.com/MailCore/mailcore2
–http://piyocast.com/as/archives/4406

tell application “Mail”
  set a to selection
  
if a = {} then error “No Selection”
  
set aa to first item of a
  
set aSource to source of aa –メールのソースを取得
end tell

set aStr to current application’s NSString’s stringWithString:aSource
set aData to aStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)

set aHeader to current application’s MCOMessageHeader’s headerWithData:aData
set aT1 to (aHeader’s subject()) as string
–> “attachment test”
set aT2 to (aHeader’s bcc())
–>  missing value
set aT3 to (aHeader’s cc())
–>  missing value
set aT4 to (aHeader’s |date|()) as date
–>  date “2017年1月20日金曜日 16:07:14″
set aT5 to (aHeader’s |from|())
–>  (MCOAddress) mailcore::Address:0×600000637ee0 Takaaki Naganoya
set aT6 to (aHeader’s inReplyTo())
–>  missing value
set aT7 to (aHeader’s receivedDate())
–>  missing value
set aT8 to (aHeader’s |references|())
–>  missing value
set aT9 to (aHeader’s replyTo())
–>  missing value
set aT10 to (aHeader’s sender())
–>  missing value
set aT11 to (aHeader’s |to|())
–>  (NSArray) {(MCOAddress) mailcore::Address:0×618000a37460 長野谷隆昌 }
set aT12 to (aHeader’s userAgent()) as string
–>  ”Apple Mail (2.3259)”
set aT13 to (aHeader’s allExtraHeadersNames()) as list
–>  {”Return-Path”, “Content-Type”, “Delivered-To”, “X-Virus-Status”, “X-Mailer”, “Received”, “Mime-Version”}
set aT14 to (aHeader’s extraHeaderValueForName:“X-Mailer”) as string
–>  ”Apple Mail (2.3259)”
set anAddress to (aHeader’s |from|())
–>  (MCOAddress) mailcore::Address:0×6180006393c0 Takaaki Naganoya
set anAdrName to (anAddress’s displayName()) as string
–>  ”Takaaki Naganoya”
set anAdrName to (anAddress’s mailbox()) as string
–>  ”maro_ml@piyocast.com”

★Click Here to Open This Script 

AppleScript名:Mail.appで選択中のメッセージから各種属性値を取得する
– Created 2017-01-23 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4406

tell application “Mail”
  set a to selection
  
if a = {} then error “No Selection”
  
set aa to first item of a
  
  
set aSub to subject of aa
  
set aBCC to bcc recipient of aa
  
set aCC to cc recipient of aa
  
set aRecL to to recipient of aa
  
set aRep to reply to of aa
  
set aRecD to date received of aa
  
set aSenD to date sent of aa
  
set aSender to sender of aa
  
log aSender
  
–User AgentはHeaderから自力で取得
  
set aHead to all headers of aa
  
–displayNameはsenderから文字列処理で自力で
  
–mailboxはsenderから文字列処理で自力 or
end tell

★Click Here to Open This Script 

2017/01/22 InputManager.frameworkでIMを切り換える

オープンソースのフレームワーク「InputManager.framework」(By Jens Nockert)を使って、IMを切り替えるじっけんを行うAppleScriptです。

im1.png

im2.png
▲これら2つ「ひらがな」「英字」の切り替えを10回繰り返します

実行のためにはInputManager.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

本Scriptの実行は言語環境を「日本語」にしてあり、macOS標準のIM「日本語入力プログラム」を利用できるようにしてある必要があります。また、本AppleScriptはControl-Command-RでScript Editor上で明示的にフロントエンド・プロセスで実行する必要があります。

AppleScript名:InputManagerでIMを切り換える
– Created 2017-01-22 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “InputManager” –https://github.com/jensnockert/input-manager
–http://piyocast.com/as/archives/4401

–Caution: This script runs on only Japanese language environment

set cList to current application’s CSInputSource’s all()
set dList to (cList’s valueForKey:“localizedName”)
set aRes to ((dList’s indexOfObject:“ひらがな”) as integer) –”Hiragana” in Japanese
set bRes to ((dList’s indexOfObject:“英字”) as integer) –”English Letters” in Japanese

set hiraKey to cList’s objectAtIndex:aRes
set engKey to cList’s objectAtIndex:bRes

repeat 10 times
  hiraKey’s |select|()
  
delay 1
  
engKey’s |select|()
  
delay 1
end repeat

★Click Here to Open This Script 

AppleScript名:IMのメニュー表示名を取得する
– Created 2017-01-22 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “InputManager” –https://github.com/jensnockert/input-manager
–http://piyocast.com/as/archives/4401

set cList to (current application’s CSInputSource’s all()’s valueForKey:“localizedName”) as list
–>  {”ひらがな”, “英字”, “カタカナ”, “日本語”, “かなパレット”, “com.apple.PressAndHold”, “絵文字と記号”, “キーボードビューア”, “EmojiFunctionRowIM_Extension”}

★Click Here to Open This Script 

2017/01/20 MailCore2でメールのeml形式ファイルから添付ファイルを抽出 v2

オープンソースのフレームワーク「MailCore2」を使ってeml形式のメールファイルを読み込んで添付ファイルを取り出すAppleScriptの改良強化版(v2)です。

実行のためにはMailCore.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

普通にMail.appをGUIなりAppleScriptから操作すれば、もっと手軽にメールの添付ファイルは取得できるわけですが、本Scriptは「うっかり書き出してしまったemlファイル」からの添付ファイルの抽出を行います。

本バージョンでは、MIMEの入れ子構造を再帰処理で追いかけています(そんなに激しく入れ子にしないと思いますが、一応)。また、添付ファイルの種別を”application/zip”だけでなく、その他のさまざまな(PDFとかExcel書類とか)ファイルについてテストして対応させてみました。

AppleScript名:MailCore2でメールのeml形式ファイルから添付ファイルを抽出 v2
– Created 2017-01-20 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MailCore” –https://github.com/MailCore/mailcore2
—http://piyocast.com/as/archives/4400

set aPath to POSIX path of (choose file of type {“com.apple.mail.email”})

set fileContents to current application’s NSData’s dataWithContentsOfFile:aPath options:(current application’s NSDataReadingMappedIfSafe) |error|:(missing value)
if fileContents = missing value then return

set aParser to current application’s MCOMessageParser’s messageParserWithData:fileContents

set aBodySet to aParser’s mainPart()
set pList to aBodySet’s parts()
set pCount to pList’s |count|()
log pCount
–> 2

set aDtPath to POSIX path of (path to desktop)

prepareMIMEpartAndSaveAttachment(pList, aDtPath) of me

–入れ子になっているMIMEの階層をたどってMessage内の添付ファイルを抽出
on prepareMIMEpartAndSaveAttachment(pList, outPath)
  repeat with i in (pList as list)
    set aMimeType to (i’s mimeType()) as string
    
set aCharset to (i’s charset()) as string
    
    
if aMimeType is in {“text/plain”, “text/html”} then
      set aStr to i’s decodedString() –とくに意味はない
      
    else if aMimeType begins with “application/” then –”application/zip” とか”application/pdf”とか
      set aData to i’s |data|()
      
set aFileName to (i’s filename()) as string
      
set fRes to writeDataToPath(outPath, aFileName, aData) of me
      
    else
      –MimeTypeとcharsetがmissing valueのpart(たぶん、Attachment)
      
set ppList to i’s parts()
      
set ppCount to ppList’s |count|()
      
prepareMIMEpartAndSaveAttachment(ppList, outPath) of me –Recursive Call
      
    end if
    
  end repeat
end prepareMIMEpartAndSaveAttachment

–NSDataをファイル書き込み。パス(aPath)はPOSIX pathで与える
on writeDataToPath(aPath, aName, aNSData)
  set newPath to aPath & aName
  
set aRes to aNSData’s writeToFile:newPath atomically:true
  
return aRes as boolean
end writeDataToPath

★Click Here to Open This Script 

2017/01/20 MailCore2でメールのeml形式ファイルから添付ファイルを抽出

オープンソースのフレームワーク「MailCore2」を使ってeml形式のメールファイルを読み込んで添付ファイルを取り出すAppleScriptです。

実行のためにはMailCore.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

普通にMail.appをGUIなりAppleScriptから操作すれば、もっと手軽にメールの添付ファイルは取得できるわけですが、本Scriptは「うっかり書き出してしまったemlファイル」からの添付ファイル(Zip圧縮したファイルのみ)の抽出を行います。

macOSのMail.appから「添付ファイルつきのメッセージ」をFinderにドラッグ&ドロップして作成したeml形式のファイルが処理対象です。

この処理対象ファイルを本AppleScriptで処理すると、デスクトップフォルダに添付ファイルが保存されます。

MIMEがマルチパートであることは認識していましたが、入れ子状態の階層が割と多い、多階層の入れ子にできるようなので、本来であれば再帰処理すべきなのかもしれません。また、Mail.app以外のメーラーから来たメールはMIMEの組み立て方が異なっているかもしれません。あくまで、macOS 10.12上のMail.app v10.2同士でやりとりした添付ファイルつきメールの処理が本Scriptで行えた、ということにすぎません。

AppleScript名:MailCore2でメールのeml形式ファイルから添付ファイルを抽出
– Created 2017-01-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MailCore” –https://github.com/MailCore/mailcore2
—http://piyocast.com/as/archives/4399

set aPath to POSIX path of (choose file of type {“com.apple.mail.email”})

set fileContents to current application’s NSData’s dataWithContentsOfFile:aPath options:(current application’s NSDataReadingMappedIfSafe) |error|:(missing value)
if fileContents = missing value then return

set aParser to current application’s MCOMessageParser’s messageParserWithData:fileContents

set aBodySet to aParser’s mainPart()
set pList to aBodySet’s parts()
set pCount to pList’s |count|()
log pCount
–> 2

set aDtPath to POSIX path of (path to desktop)

–本来は再帰で処理すべき?
repeat with i in (pList as list)
  set aMimeType to (i’s mimeType()) as string
  
–> “text/plain”
  
  
set aCharset to (i’s charset()) as string
  
–> “UTF-8″
  
  
if aMimeType is in {“text/plain”, “text/html”} then
    set aStr to i’s decodedString()
    
  else if aMimeType = “application/zip” then
    set aData to i’s |data|()
    
set aFileName to (i’s filename()) as string
    
set fRes to writeDataToPath(aDtPath, aFileName, aData) of me
    
log fRes
    
  else
    –MimeTypeとcharsetがmissing valueのpart(たぶん、Attachment)
    
set ppList to i’s parts()
    
set ppCount to ppList’s |count|()
    
    
repeat with ii in (ppList as list)
      set bMimeType to (ii’s mimeType()) as string
      
set bCharset to (ii’s charset()) as string
      
      
if bMimeType is in {“text/plain”, “text/html”} then
        set aStr to ii’s decodedString()
        
      else if bMimeType = “application/zip” then
        set bData to ii’s |data|()
        
set bFileName to (ii’s filename()) as string
        
log bFileName
        
set fRes to writeDataToPath(aDtPath, bFileName, bData) of me
        
log fRes
      end if
    end repeat
    
  end if
  
end repeat

–NSDataをファイル書き込み。パス(aPath)はPOSIX pathで与える
on writeDataToPath(aPath, aName, aNSData)
  set newPath to aPath & aName
  
set aRes to aNSData’s writeToFile:newPath atomically:true
  
return aRes as boolean
end writeDataToPath

★Click Here to Open This Script 

2017/01/18 MailCore2でメールのeml形式ファイルを読み込む v2

オープンソースのフレームワーク「MailCore2」を使ってeml形式のメールファイルを読み込んでテキスト化するAppleScriptです。

実行のためにはMailCore.frameworkをビルドして、~/Library/Frameworksに入れておく必要があります。

本来、Mail.appでメールから本文テキストを取得するのは簡単で、小学生レベルの処理内容ですが本AppleScriptは、Mail.appから書き出されたemlファイル(Mail.appからドラッグ&ドロップで単体のメールを書き出したファイル)からの本文抽出を行います。

mail_eml.png

AppleScriptでなんともならない書類の筆頭であった「.eml」形式ファイルを読み込んでプレーンテキスト化できるようになったことには、大きな意義があるような気がします。

AppleScript名:MailCore2でメールのeml形式ファイルを読み込む v2
– Created 2017-01-18 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MailCore” –https://github.com/MailCore/mailcore2
—http://piyocast.com/as/archives/4397

set aPath to POSIX path of (choose file of type {“com.apple.mail.email”})

set fileContents to current application’s NSData’s dataWithContentsOfFile:aPath options:(current application’s NSDataReadingMappedIfSafe) |error|:(missing value)
if fileContents = missing value then return

set aParser to current application’s MCOMessageParser’s messageParserWithData:fileContents

–改行を削除してメール本文をプレーンテキスト化
set aBody1 to (aParser’s plainTextBodyRendering()) as string
–>  ”技術書典 事務局です。 この度は技術書典2へのサークル参加申し込み、誠にありがとうございました。 ◎貴サークル「Piyomaru Software」は、 え-11 に配置されました。…

–改行を維持しつつメール本文をプレーンテキスト化
set aBody2 to (aParser’s plainTextBodyRenderingAndStripWhitespace:false) as string
(*
–>  ”技術書典 事務局です。
この度は技術書典2へのサークル参加申し込み、誠にありがとうございました。
◎貴サークル「Piyomaru Software」は、 え-11 に配置されました。
*)

★Click Here to Open This Script 

2017/01/17 MJProjectKitでXcode Projectにアクセスして詳細な情報を取得する

オープンソースのフレームワーク「MJProjectKit」(By Martin Johannesson)を使ってXcode Projectにアクセスし、詳細な情報を取得するAppleScriptです。

同フレームワークは、これだけ破壊力が大きいものなのにあまり有名ではありませんでした。理由はいまひとつわかりませんが、おそらく「使い方がどこにも書かれていなかった」ためではないかと思います。

自分も「なんかいい感じのフレームワークかも」と思いつつ、呼び出しを試してみたものの、エラーが出るばかりでさっぱりでした。

現在のXcode project書類「.xcodeproj」はバンドル・パッケージであり、その実体はフォルダです。そこで、バンドル内のファイルまで選択できるように指定し、バンドル内の「project.pbxproj」を指定したところ問題なくXcode Projectの詳細情報にアクセスできました。ファイル選択→Xcode Projectへのアクセスのあたりのサンプルが出ていないと、さすがに使えないと思います(ーー;

dialog21.png

dialog22.png

本AppleScriptを実行するためには、MJProjectKitをビルドして~/Library/Frameworksフォルダに入れておく必要があります。

MJProjectKitは現行のXcode 8を完全にフォローできていないのか、まだ機能が不完全なためか、同フレームワークが用意しているオブジェクト階層をたどるための機能を使ってもうまく行かず、プロジェクト全体の情報をとってきて自前で階層構造をたどったほうがうまく行きそうな気配がしています(作業量が多くてたいへん)。

MJProjectKitは2013年以降メンテナンスされておらず、apparataによりSwiftで書き直された「ProjectKit」のプロジェクトのほうが活発なようです。

Github上でのMartin Johannessonの活動を調べてみると、このProjectKitに関与しているようで、目下apparataの一員として活動しているということなのでしょう。

AppleScript名:MJProjectKitでXcode Projectにアクセスして詳細な情報を取得する
– Created 2017-01-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “MJProjectKit” –https://github.com/memfrag/MJProjectKit
–http://piyocast.com/as/archives/4394

set aFile to POSIX path of (choose file with prompt “Select <project .pbxproj> file inside .xcodeproj bundle” with showing package contents)
set aURL to current application’s |NSURL|’s fileURLWithPath:aFile
set xCodePrj to current application’s MJProjectFile’s projectFileWithContentsOfURL:aURL |error|:(missing value)

set projList to xCodePrj’s specification()
set objList to objects of projList
set keyList to objList’s allKeys()
set keyEmu to keyList’s objectEnumerator()
set nArray to current application’s NSMutableArray’s alloc()’s init()

repeat
  set aKey to keyEmu’s nextObject()
  
if aKey = missing value then exit repeat
  
set aVal to objList’s valueForKey:aKey
  
set aKind to (aVal’s isa) as string
  
  
set eachKeyList to (aVal’s allKeys()) as list
  
  
repeat with i in eachKeyList
    set j to contents of i
    
set eachVal to (aVal’s valueForKey:j)
    
log {j, eachVal’s |description|() as string} –To support Apple’s Script Editor
  end repeat
  
end repeat

★Click Here to Open This Script 

2017/01/16 DSCaptureで画面キャプチャ

オープンソースの画面キャプチャフレームワーク「DSCapture.framework」(By kiding)をビルドしてAppleScriptから呼び出してみました。

まずは、フレームワークをビルドして~/Library/Frameworksフォルダに入れてください。

DSCaptureには、

 (1)スクリーン全体をキャプチャ(複数枚のモニタがつながっている場合には結果がすべて配列に入る。モニタ1枚でも配列)
 (2)ユーザー選択範囲をキャプチャ

の機能があります。本サンプルでは、キャプチャした画像をデスクトップにPNG形式で保存します。

このため、screencaptureコマンドと機能的にはかわりません(座標を指定してキャプチャできるといいのに)。

→ キャプチャしたあとで切り抜けば問題なさそうです

AppleScript名:DSCaptureで画面キャプチャ
– Created 2017-01-16 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “DSCapture” –https://github.com/kiding/DSCapture.framework
use framework “AppKit”
–http://piyocast.com/as/archives/4393

–Full Screen (Every Display)
set aCapt to current application’s DSCapture’s sharedCapture()’s |full|()’s captureWithTarget:me selector:“displayCaptureData:” useCG:false

–Selected Area (Selected Area Only by user operation)
set bCapt to current application’s DSCapture’s sharedCapture()’s |selection|()’s captureWithTarget:me selector:“displayCaptureData:” useCG:false

–Delegate Handler
on displayCaptureData:aSender
  set aCount to aSender’s |count|()
  
repeat with i from 0 to (aCount - 1)
    set anImage to (aSender’s imageAtIndex:i)
    
    
–Make Save Image Path
    
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”))
    
saveNSImageAtPathAsPNG(anImage, savePath) of me
    
  end repeat
end displayCaptureData:

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
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 saveNSImageAtPathAsPNG

★Click Here to Open This Script 

2017/01/15 PDFlib GmbHのPDFlibを呼ぶじっけん【未遂】

データからPDFを出力するためのPDFlib GmbHの多機能コンポーネント「PDFlib」をためしてみました。同フレームワークはWindows Server/Linux Server/OS X Server/Oracle Solaris/IBM AIX/HP-UX/Windows XP, Vista, 7, 8/OS X desktop/iOS向けに製品が提供されています。日本国内では株式会社テックスタイルが総代理店になっているとのこと。

pdflib_man.png

Objective-Cのサンプルコードを見ていたらそれほど難しくなかったので、AppleScriptでalloc()してinit()して問題なし。ただ、次の行で困りました。

PDFlib内部のメソッド名に「_」(アンダースコア)が使用されていたため、AppleScriptObjCのメソッド名変換にひっかかって、メソッドを呼び出すことができませんでした(残念!)。

OS X desktopの「pCOS 4」(PDF情報抽出系)ライセンス料は22,000円とのこと。自動処理専用システム用にAdobe Illustrator CCをライセンス料を支払いながら使うことを考えれば、PDFからのテキスト抽出を行うためのライブラリとして併用できたら便利かと思って試してみたのですが、ちょっとだけ残念です。

AppleScript名:PDFlib GmbHのPDFlibを呼ぶじっけん
– Created 2017-01-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “PDFlib” –PDFlib GmbH’s PDFlib
–http://piyocast.com/as/archives/4391

set aFile to POSIX path of (choose file of type {“com.adobe.pdf”})
set aPDFlib to current application’s PDFlib’s alloc()’s init()
aPDFlib’s |set_option:|(“errorpolicy=exception”) –Error

★Click Here to Open This Script 

2017/01/15 display alert命令でMacBook Pro Late 2016のtouch barにボタン表示

いろいろホットな話題を世間に振りまいているMacBook Pro Late 2016。その実機を持っている知人に実際にためさせてもらい、display alert命令で画面上に表示したダイアログと同じボタンがTouch Barに表示されることを確認しました。

display alert命令のボタンがTouch barに表示されることは、ソフトウェアベースのTouch Barシミュレータ「Touch Bar Server」で確認していました。また、display dialogコマンドではTouch Barにボタンの内容が表示されないことも、確認していました。

displayalert.png

img_0185_resized.png

AppleScript名:touch bar test
display alert “test” buttons {“1″, “2″, “3″}

★Click Here to Open This Script 

2017/01/13 デコードしたQRコードのメールデータの各フィールドを取り出す v2.2

メールアドレス、Subject、Bodyの各フィールドが同梱されたQRコードをデコードした文字列を、docomo形式のフィールド形式と見立てて、各フィールドを取り出すAppleScriptです。

test_qr.png
–> “MATMSG:TO:hiyoko@piyocast.com;SUB:たいとる;BODY:ほんぶん;;”

こんな(↑)QRコードを読み取って、文字列にデコードできるわけですが、携帯電話用のQRコードはもともと、

名刺データ(氏名、住所など)交換、Webブックマーク(名前とURL)読み取り、メール文面生成などを目的として作られたため(フリー形式もありますけれども)、単にデータをデコードしただけではなく、これらのデータ形式であるかどうかのチェックが必要です。

これらのデータ形式だった場合には、それぞれフィールド値を取り出す必要があるわけですが、ここではメール文面の生成のみ対象にしています。

さて、各フィールドを解釈しようとしても、日本には主に3つの携帯電話キャリアがあり(docomo、au、softbank)、それぞれ微妙にこのフィールド定義形式が異なります。

調査したところ、docomo形式でないと読み取れないiOSアプリがあったため、docomo形式をデコードすることにします(AppStoreでも5本ぐらいのiOSアプリしかフィールド検出できませんでした)。海外産のiOSアプリでQRコードのこれらのデータ形式に対応しているケースではdocomo形式にのみ対応しているようでした(それでもあまたの未対応iOSアプリの1億倍えらい)。

先日、国内外のマニアさんによって寄ってたかって改良されまくった「&と=で区切られたテキストをrecordに(NSScanner版)」をもとに若干の手直しを行い、このためのサブルーチンに作り変えてみました。

Cocoaを呼び出すことで、AppleScript単体で(他のアプリケーションの力を借りずに)QRコードの作成や認識はできていますが、実際には携帯電話側でQRコードを読み取り、その内容をメールでMac側に転送し、Mac側で評価するような運用を想定しています。本Scriptはそのための「準備段階」のものです。

だいたいは、スマホでQRコードをスキャンして、その情報をメールで送ってくるので、Mac側で処理することを考えると、本文にデータが入ってくることだけを見ていればいいはずです。なので、スマホから来たデータ処理のためにはこんなたいそうなルーチンは必要ありません。

一応、Mac側でQRコードをデコードしたあとの「解釈」を行えるようにしておくことは無駄にはならないでしょう。

AppleScript名:デコードしたQRコードのメールデータの各フィールドを取り出す v2.2
– Created 2016-12-12 by Shane Stanley
– Modified 2016-12-14 by edama2
– Modified 2017-01-12 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4387

set aStr to “こんにちは、ぴよまるです

MATMSG:TO:hiyoko@piyocast.com;SUB:たいとる;BODY:ほんぶん;;

Takaaki Naganoya
XXX-XXXX-XXXX

iPhoneから送信”

set aDict to (parseStrByParamlabelAndTail(aStr, “MATMSG:”, “:”, “;”) of me)

set eMailAddrs to (aDict’s valueForKey:“TO”) as string
–>  ”hiyoko@piyocast.com”
set aSubject to (aDict’s valueForKey:“SUB”) as string
–>  ”たいとる”
set aBody to (aDict’s valueForKey:“BODY”) as string
–>  ”ほんぶん”

on parseStrByParamlabelAndTail(aParamStr, aDataHeader, aParamLabel, aParamTail)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set aDict to current application’s NSMutableDictionary’s |dictionary|()
  
  
—Skip over the data header
  
set {theResult, theKey} to theScanner’s scanUpToString:aDataHeader intoString:(reference)
  
if theResult as boolean = false then return false –Error: Data header is not present
  
  
theScanner’s scanString:aDataHeader intoString:(missing value)
  
  
repeat until (theScanner’s isAtEnd as boolean)
    – terminate check, return the result (aDict) to caller
    
set {theResult, theKey} to theScanner’s scanUpToString:aParamLabel intoString:(reference)
    
    
– skip over separator
    
theScanner’s scanString:aParamLabel intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:aParamTail intoString:(reference)
    
if theValue is missing value then set theValue to “”
    
    
– skip over separator
    
theScanner’s scanString:aParamTail intoString:(missing value)
    
    
aDict’s setObject:theValue forKey:theKey
  end repeat
  
  
return aDict
end parseStrByParamlabelAndTail

★Click Here to Open This Script 

2017/01/10 Keynote書類の画像書き出しテスト

Keynote書類をデスクトップに画像書き出し(PNG形式)するAppleScriptです。動作確認はmacOS 10.12.3beta+Keynote 7.0.5で行っています。

macOS 10.12.x+Keynote 7.0.5ではSandbox化の影響を受けてexportコマンドがうまく動作していないようで、そのままPDF書き出しを実行するとError 6に遭遇しました。これを回避するために、PDF書き出し前にPDFと同名の空のファイルを作るとよいことがわかりました。

sandboxed_export.png

AppleScriptからKeynoteに書類の画像書き出しを行うとError 6に遭遇するのはPDF書き出しと事情は変わりません。何らかの対策を行う必要があります。

画像書き出しは指定の場所にフォルダが作成されて、さらにその中にスライド画像が連番つきで書き出されます。1つのPDFができるPDF書き出しとは若干動作が異なるわけです。

試行錯誤したところ、書き出しフォルダと同じ名前のフォルダを、画像書き出し前にあらかじめ作っておけばエラーを回避できることがわかりました。

同様に、macOS 10.12上ではSandbox化されたアプリケーション上でのexportコマンドの挙動に問題があることが報告されており、ここで示したようなやり方で回避できているようです。具体的には、Mailの添付ファイルの書き出しがこれでSandbox由来のエラーを回避できた事例が報告されています。

一方で、Microsoft Word 2016/Excel 2016においてAppleScriptからExportを行わせたときに上記の回避策ではSandbox由来のエラーを回避できず、海外のScripter連中と回避策を相談しているところです。

Appleにはフィードバック済みですが、かなり問題のある動作に見えます。

AppleScript名:Keynote書類の画像書き出しテスト
– Created 2017-01-10 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4384

tell application “Keynote”
  if (count every document) = 0 then error “There is no Keynote Document”
  
set aDoc to document 1
end tell
set kRes to exportImagesFromKeynote(aDoc) of me

on exportImagesFromKeynote(aDoc)
  tell application “Keynote”
    set aPath to file of aDoc
  end tell
  
  
set tmpPath to (path to desktop) as string
  
set curPath to (current application’s NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()
  
set outPath to (tmpPath & curPath)
  
  
–This preliminary process may be no use if macOS or Keynote fixed in the future
  
do shell script “mkdir “ & quoted form of POSIX path of outPath –To Avoid “Error 6″ (Keynote 7.0.5+macOS 10.12.2/3)
  
–This preliminary process may be no use if macOS or Keynote fixed in the future
  
  
tell application “Keynote”
    set anOpt to {class:export options, compression factor:1.0, image format:PNG, export style:IndividualSlides, all stages:false, skipped slides:true}
    
export document 1 to file outPath as slide images with properties anOpt
  end tell
  
  
return (outPath as alias)
end exportImagesFromKeynote

★Click Here to Open This Script 

2017/01/09 PDFのしおり(TOC)の内容を取得するじっけん v2

指定のPDFにしおり(TOC: Table Of Contents)がついていたら、その内容を読み取るじっけんです。再帰処理でTOCの階層を追いかけるようにしてみました。

2階層までのTOCのPDFを処理するScriptと処理結果を照合して、同じであることを確認していますが、3階層以上の深さを持つTOCでテストは行っていません。

AppleScript名:PDFのしおり(TOC)の内容を取得するじっけん v2
– Created 2017-01-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4383

property titleList : {}

set my titleList to {}

set aFile to POSIX path of (choose file of type {“com.adobe.pdf”})
tell current application
  set fileURL to my (|NSURL|’s fileURLWithPath:aFile)
  
set aPDFdoc to my (PDFDocument’s alloc()’s initWithURL:fileURL)
end tell

–TOCの読み込み
set parentOL to aPDFdoc’s outlineRoot() –あらかじめTOCが存在していないとmissing valueになる
if parentOL is equal to missing value then
  display dialog “本PDFにはTOCが添付されていないため、処理を終了します” with title “No TOC Error:”
  
return
end if

getChilds(parentOL) of me
return my titleList

–再帰処理してみた
on getChilds(parentOL)
  set outLineStr to parentOL’s label()
  
set outLineCount to (parentOL’s numberOfChildren()) as number
  
  
repeat with i from 0 to (outLineCount - 1)
    set anOut to (parentOL’s childAtIndex:i)
    
set tmpOut to (anOut’s label()) as string
    
set the end of my titleList to tmpOut
    
set tmpChild to (anOut’s numberOfChildren()) as integer
    
    
if tmpChild is not equal to 0 then
      getChilds(anOut) of me
    end if
  end repeat
end getChilds

★Click Here to Open This Script 

2017/01/09 PDFのしおり(TOC)の内容を取得するじっけん

指定のPDFにしおり(TOC: Table Of Contents)がついていたら、その内容を読み取るじっけんです。

Cocoa経由でも意外とたいした情報が取得できないところが驚きです。TOCの階層が2階層になっているものを処理の前提条件にしているので、本Scriptの仕様では3階層以上潜っていけません。

単なる実験なので、もう少し何か気の利いた処理ができるとよいでしょう。再帰処理とか。

AppleScript名:PDFのしおり(TOC)の内容を取得するテスト
– Created 2017-01-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “Quartz”
–http://piyocast.com/as/archives/4382

set aFile to POSIX path of (choose file of type {“com.adobe.pdf”})
tell current application
  set fileURL to my (|NSURL|’s fileURLWithPath:aFile)
  
set aPDFdoc to my (PDFDocument’s alloc()’s initWithURL:fileURL)
end tell

–TOCの読み込み
set parentOL to aPDFdoc’s outlineRoot() –あらかじめTOCが存在していないとmissing valueになる
if parentOL is equal to missing value then
  display dialog “本PDFにはTOCが添付されていないため、処理を終了します” with title “No TOC Error:”
  
return
end if

set outLineStr to parentOL’s label() –numberOfChildren()
set outLineCount to (parentOL’s numberOfChildren()) as number
set titleList to {}

–本当は再帰処理したいが…
repeat with i from 0 to (outLineCount - 1)
  
  
set anOut to (parentOL’s childAtIndex:i)
  
set tmpOut to (anOut’s label()) as string
  
set the end of titleList to {0, tmpOut}
  
set tmpChild to (anOut’s numberOfChildren()) as integer
  
  
if tmpChild is not equal to 0 then
    repeat with ii from 0 to (tmpChild - 1)
      set anOut2 to (anOut’s childAtIndex:ii)
      
set tmpOut2 to (anOut2’s label()) as string
      
set the end of titleList to {1, tmpOut2}
    end repeat
  end if
  
end repeat

return titleList
–>  {{0, “表紙”}, {0, “目次”}, {0, “まえがき”}, {0, “この書籍について”}, {0, “#1 アプリケーションメニュー”}, {1, “アプリケーションメニュー”}, {1, “アプリケーション名称の取得”}, {1, “バージョン情報の取得”}, {1, “アップデートを確認”},….}

★Click Here to Open This Script 

2017/01/09 Keynote書類をデスクトップにPDFで出力する

Keynote書類をデスクトップにPDFで出力するAppleScriptです。動作確認はKeynote v7.0.5で行いました(初回掲載分からアップデート)。

Keynoteから出力したPDFに対し、Keynote書類の構造を確認しつつ、階層構造つきのTOC(しおり)を付加するAppleScriptを作成したときに作ったものです(KeynoteでPDF書き出ししただけでは、階層構造つきのTOCなんて気のきいたものはついてきませんので)。

keynote_leveled_toc.png

exportコマンドによる出力先のフォルダに、当初temporary items folderを指定してみたのですが、ユーザー権限がないと言われて書き込めませんでした。Keynoteはサンドボックス化されたアプリケーションなので、ホームディスレクトリの下のどこかを一時作業フォルダとして使うように運用を変更する必要があることでしょう(temporary items folderの存在意義が、、、、)。

【重要! 生死に関わるレベル】

macOS 10.12.3beta上で、exportコマンド実行時にエラー(Error 6)になることがあり、原因 を調査したところ、すでにexport先に同名のファイルが存在する場合にはエラーにならないことがわかりました。Sandbox化の影響を受け、Keynote自体がファイルを書き出せない状態にあったようなので、shellのtouchコマンドで書き出すPDFと同名の(空っぽの)ファイルをあらかじめ作成しておいてからexportコマンドを実行したところうまく行きました。

AppleScript名:Keynote書類をデスクトップにPDFで出力する v1.1
– Created 2017-01-09 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4380

tell application “Keynote”
  set dCount to count every document
end tell

if dCount = 0 then
  display dialog “オープン中のKeynote書類はありません” with icon 0 with title “No Document Error”
  
return
end if

tell application “Keynote”
  set aPath to file of document 1
end tell

–Keynote書類のファイル名だけを取り出し、拡張子を外し、別の拡張子(.pdf)を追加する
set curPath to (current application’s NSString’s stringWithString:(POSIX path of aPath))’s lastPathComponent()’s stringByDeletingPathExtension()’s stringByAppendingString:“.pdf”

set tmpPath to (path to desktop) as string
set outPath to tmpPath & (curPath as string)

do shell script “touch “ & quoted form of POSIX path of outPath

tell application “Keynote”
  set anOpt to {class:export options, export style:IndividualSlides, all stages:false, skipped slides:true, PDF image quality:Best}
  
export document 1 to file outPath as PDF with properties anOpt
end tell

★Click Here to Open This Script 

2017/01/07 iTunesライブラリの曲のアーティスト名を集計

iTunesライブラリ中に入っている「曲」(song)のアーティスト名を集計するAppleScriptです。

iTunesLibraryフレームワークを用いてライブラリにアクセスしているので、iTunes.appが起動している必要はありません。

アーティスト名については、ライブラリ中にかなりイレギュラーなデータが存在しているため、対策が必要でした。

・初期のiTunesで、CDからリッピングしたものの、CDDBに登録がなかったため、アーティスト名などが登録されていない→ エラートラップで対処

・アーティスト名で姓(last name)と名(first name)の間に空白が入っていたりいなかったりするなど、表記ゆらぎが存在していたため、ゆらぎを吸収

もう少し高速に実行できてもよさそうですが、ライブラリ中のtrackが8,100程度のときに、10回実行時の平均は2.8秒程度です(MacBook Pro Retina 2012)。

AppleScript名:iTunesライブラリの曲のアーティスト名を集計
– Created 2017-01-07 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “iTunesLibrary”
–http://piyocast.com/as/archives/4379

set library to current application’s ITLibrary’s libraryWithAPIVersion:“1.0″ |error|:(missing value)
if library is equal to missing value then return

set allTracks to library’s allMediaItems()
set allCount to allTracks’s |count|()

set anEnu to allTracks’s objectEnumerator()
set newArray to current application’s NSMutableArray’s alloc()’s init()

repeat
  set aPL to anEnu’s nextObject()
  
if aPL = missing value then exit repeat
  
try
    set aKind to (aPL’s mediaKind) as integer
    
    
if (aKind as integer) is equal to 2 then –Music, Song
      set plName to aPL’s artist’s |name| as string
      
set pl2Name to (my changeThis:” “ toThat:“” inString:plName) –日本語アーティスト名で姓と名の間にスペースが入っているものがある(表記ゆらぎ)ので対策
      
newArray’s addObject:(pl2Name)
    end if
  on error
    set aLoc to (aPL’s location’s |path|()) as string
    
log aLoc
  end try
end repeat

set aRes to countItemsByItsAppearance(newArray) of me
–>  {{theName:”浜田省吾”, numberOfTimes:442}, {theName:”B’z”, numberOfTimes:379}, {theName:”渡辺岳夫・松山祐士”, numberOfTimes:199}, {theName:”VariousArtists”, numberOfTimes:192}, {theName:”菅野よう子”, numberOfTimes:108}, {theName:”布袋寅泰”, numberOfTimes:100}, {theName:”三枝成彰”, numberOfTimes:95}, {theName:”宇多田ヒカル”, numberOfTimes:94}, {theName:”宮川泰”, numberOfTimes:81}, {theName:”MichaelJackson”, numberOfTimes:78}, {theName:”稲葉浩志”, numberOfTimes:73}, …

–出現回数で集計
on countItemsByItsAppearance(aList)
  set aSet to current application’s NSCountedSet’s alloc()’s initWithArray:aList
  
set bArray to current application’s NSMutableArray’s array()
  
set theEnumerator to aSet’s objectEnumerator()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
bArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (aSet’s countForObject:aValue)} forKeys:{“theName”, “numberOfTimes”})
  end repeat
  
  
–出現回数(numberOfTimes)で降順ソート
  
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“numberOfTimes” ascending:false
  
bArray’s sortUsingDescriptors:{theDesc}
  
  
return bArray as list
end countItemsByItsAppearance

on changeThis:findString toThat:repString inString:someText
  set theString to current application’s NSString’s stringWithString:someText
  
set theString to theString’s stringByReplacingOccurrencesOfString:findString withString:repString options:(current application’s NSRegularExpressionSearch) range:{location:0, |length|:length of someText}
  
return theString as text
end changeThis:toThat:inString:

★Click Here to Open This Script 

2017/01/05 iCal4ObjCのじっけん

オープンソースのiCalendarファイルの読み込み/作成を行うフレームワーク「iCal4ObjC」(By Satoshi Konno)をビルドしてAppleScriptから呼び出してみました。

iCalendarファイルの生成については、カレンダー.app(旧称:iCal)を使う方法もありますが、同アプリはApple純正アプリケーションの中でもトップクラスの「動作内容に信用がおけない」ものなので、こうして他のプログラム経由でも読み書きできるようにしておくことは重要と思われます。

とりあえず、OS X 10.10以降で動作するようにiCal4ObjCをFramework化してビルドしたバイナリを用意しておきました。自己責任でframeworkを~/Library/Frameworksフォルダ以下にアーカイブを展開してコピーしたうえで本Scriptをおためしください。

–> Download Framework Binary

AppleScript名:iCal4ObjCのじっけん(iCalendarファイルの作成)
– Created 2017-01-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “iCalendarKit”
–https://github.com/cybergarage/iCal4ObjC
–http://piyocast.com/as/archives/4377

set aCal to current application’s CGICalendar’s alloc()’s init()

–Add a object
set aCalObj to current application’s CGICalendarObject’s alloc()’s initWithProdid:“//CyberGarage//iCal4ObjC//EN”
aCal’s addObject:aCalObj

–Add a component
set aCalComp to current application’s CGICalendarComponent’s alloc()’s initWithType:“VTODO”
aCalObj’s addComponent:aCalComp

–Add a property
set aCalProp to current application’s CGICalendarProperty’s alloc()’s init()
aCalProp’s setName:“SUMMARY”
aCalProp’s setValue:“Write report”
aCalComp’s addComponent:aCalProp

–Write to File
set aFilePath to POSIX path of (((path to desktop) as string) & (current application’s NSUUID’s UUID()’s UUIDString()) as string) & “.ics”
set calRes to (aCal’s writeToFile:aFilePath) as boolean

★Click Here to Open This Script 

AppleScript名:iCal4ObjCのじっけん(iCalendarファイルのparse)
– Created 2017-01-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “iCalendarKit”
–https://github.com/cybergarage/iCal4ObjC
–http://piyocast.com/as/archives/4377

set aCalFile to POSIX path of (choose file of type {“com.apple.ical.ics”} with prompt “ICSファイルを選択”)

set aCal to current application’s CGICalendar’s alloc()’s init()
if (aCal’s parseWithPath:aCalFile |error|:(missing value)) as boolean is not equal to true then
  error “ics parse error”
end if

–iCalendar(.ics)ファイル中には複数のカレンダー情報が含まれる可能性があるため、ループ処理
set icalObjList to (aCal’s objects()) as list

repeat with i in icalObjList
  set j to contents of i
  
set compList to (j’s components()) as list
  
  
repeat with i2 in compList
    set j2 to contents of i2
    
    
repeat with i3 in j2’s |properties|()
      set j3 to contents of i3
      
set iCalPropName to j3’s |name|()
      
set iCalPropValue to j3’s value()
      
      
repeat with i4 in (j3’s parameters())
        set j4 to contents of i4
        
set icalParamName to j4’s |name|()
        
set iCalPropValue to j4’s value()
        
log {icalParamName, iCalPropValue}
      end repeat
    end repeat
  end repeat
end repeat

★Click Here to Open This Script 

2017/01/05 XPathQuery4ObjCのじっけん

オープンソースのXML/RSSのパーサー「XPathQuery for Objective-C」(By Satoshi Konno)をCocoa FrameworkにビルドしてAppleScriptから呼び出してみました。

いくつも試してはみたものの、なかなかしっくりくるRSSのパーサーがなかったのですが、これまで試した中では一番いい感じです(当社比)。

とりあえず、OS X 10.10以降で動作するようにXPathQuery4ObjCをFramework化してビルドしたバイナリを用意しておきました。自己責任でframeworkを~/Library/Frameworksフォルダ以下にアーカイブを展開してコピーしたうえで本Scriptをおためしください。

–> Download Framework Binary

AppleScript名:XPathQuery4ObjCのじっけん
– Created 2017-01-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XPathQueryKit”
–https://github.com/cybergarage/XPathQuery4ObjC
–http://piyocast.com/as/archives/4376

set rssURL to current application’s |NSURL|’s URLWithString:“http://rss.news.yahoo.com/rss/topstories”
set xpathQuery to current application’s CGXPathQuery’s alloc()’s initWithContentsOfURL:rssURL

if ((xpathQuery’s parse()) as boolean) = true then
  set aTitle to xpathQuery’s valueForXPath:“/rss/channel/title”
  
set entriesList to xpathQuery’s objectsForXPath:“/rss/channel/item”
  
  
repeat with xpathObject in entriesList
    
    
set entryTitle to (xpathObject’s valueForXPath:“title”)
    
log {entryTitle as string}
    
    
set linkURL to (current application’s |NSURL|’s URLWithString:(xpathObject’s valueForXPath:“link”))
    
log {linkURL’s absoluteString() as string}
    
    
set mediaContent to (xpathObject’s objectForXPath:“media:content”)
    
    
if mediaContent is not equal to missing value then
      set anAttr to mediaContent’s attributes()
      
set anImageURL to (current application’s |NSURL|’s URLWithString:((mediaContent’s attributes())’s valueForKey:“url”))
      
log {anImageURL’s absoluteString() as string}
    end if
    
  end repeat
  
end if

★Click Here to Open This Script 

AppleScript名:XPathQuery4ObjCのじっけん2
– Created 2017-01-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XPathQueryKit”
–https://github.com/cybergarage/XPathQuery4ObjC
–http://piyocast.com/as/archives/4376

set rssURL to current application’s |NSURL|’s URLWithString:“http://piyocast.com/as/feed”
set xpathQuery to current application’s CGXPathQuery’s alloc()’s initWithContentsOfURL:rssURL

if ((xpathQuery’s parse()) as boolean) = true then
  set entriesList to xpathQuery’s objectsForXPath:“/rss/channel/item”
  
  
repeat with itemObject in entriesList
    set aChild to itemObject’s children()
    
log aChild
    
    
set aTitle to (itemObject’s valueForXPath:“title”)
    
log aTitle as string
    
    
set aLink to (itemObject’s valueForXPath:“link”)
    
log aLink as string
    
    
set aComments to (itemObject’s valueForXPath:“comments”)
    
log aComments as string
    
    
set aPubdate to (itemObject’s valueForXPath:“pubDate”)
    
log aPubdate as string
    
    
set aCreator to (itemObject’s valueForXPath:“dc:creator”)
    
log aCreator as string
    
    
set aCategory to (itemObject’s valuesForXPath:“category”)
    
log aCategory as list
    
    
set aGUID to (itemObject’s valuesForXPath:“guid”)
    
log aGUID as string
    
    
set aDesc to (itemObject’s valueForXPath:“description”)
    
log aDesc as string
    
    
set aCommentURL to (itemObject’s valueForXPath:“wfw:commentRss”)
    
log aCommentURL as string
  end repeat
  
end if

★Click Here to Open This Script 

2017/01/03 Notesの指定エントリの本文をプレーンテキストとして取得

macOS標準搭載アプリ「メモ」(英語名:Notes)の指定エントリの本文をプレーンテキストとして取得するAppleScriptです。

メモの本文(body)がHTMLとして取得されるので、HTMLからスタイル付きテキスト(NSAttributedString)を経由してプレーンテキストに変換します。

AppleScript名:Notesの指定エントリの本文をプレーンテキストとして取得
– Created 2017-01-03 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

tell application “Notes”
  tell note 1 –とりあえず最新のエントリを指定
    set theBody to body
  end tell
end tell

set anNSString to current application’s NSString’s stringWithString:theBody
set theData to anNSString’s dataUsingEncoding:(current application’s NSUTF16StringEncoding)
set styledString to current application’s NSAttributedString’s alloc()’s initWithHTML:theData documentAttributes:(missing value)

set plainText to (styledString’s |string|()) as string

★Click Here to Open This Script 

2017/01/03 NSMapTableのじっけん

どうしてもNSMapTableを作って呼び出す必要のある部品があって、仕方なくNSMapTableについて調査。「NSMutableDictionaryとほぼ同じだがメモリー上の管理方式が異なる」という以上の説明がなく、なかなか強敵です。

しかも、NSDictionary/NSMutableDictionaryから変換するメソッドなどもないため、なかなか作るのもめんどくさいと来ています。

NSMapTable自体を操作するメソッドも少ないので、AppleScript側にとってあまりメリットはなさそうですが、とりあえずNSDictionary/NSMutableDictionaryとの間で相互変換できるようにしてみました。

AppleScript名:NSMapTableのじっけん
– Created 2017-01-02 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–AppleScriptではStrongでもWeakでも関係ない???
set aMapTable to current application’s NSMapTable’s mapTableWithKeyOptions:(current application’s NSMapTableStrongMemory) valueOptions:(current application’s NSMapTableStrongMemory)

–set aMapTable to current application’s NSMapTable’s mapTableWithKeyOptions:(current application’s NSMapTableWeakMemory) valueOptions:(current application’s NSMapTableWeakMemory)

aMapTable’s setObject:“1″ forKey:“foo1″
aMapTable’s setObject:“2″ forKey:“foo2″
aMapTable’s |count|()
–> 2

aMapTable’s objectEnumerator()’s allObjects() as list –objects
–>  {”2″, “1″}

aMapTable’s keyEnumerator()’s allObjects() as list –keys
–>  {”foo2″, “foo1″}

aMapTable’s dictionaryRepresentation() as record –NSMapTable to NSDictionary to record
–>  {foo:”1″, foo2:”2″}

–以下はあまり関係ない?
–aMapTable’s keyPointerFunctions()
–>  (NSConcretePointerFunctions)

–aMapTable’s valuePointerFunctions()
–>  (NSConcretePointerFunctions)

★Click Here to Open This Script 

record –> NSMutableDictionary –> NSMapTable と変換するサブルーチンも作ってみました。

AppleScript名:NSMapTableのじっけん(NSDictionary to NSMapTable)
– Created 2017-01-02 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aRec to {foo1:1, foo2:2, foo3:3, foo4:4, foo5:5}
set aDict to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
set aMap to convertDictToMap(aDict) of me
(*
–>  (NSConcreteMapTable) NSMapTable {
[1] foo2 -> 2
[5] foo4 -> 4
[7] foo5 -> 5
[11] foo3 -> 3
[14] foo1 -> 1
}
*)


–Verify
set bDict to aMap’s dictionaryRepresentation() as record
–>  {foo1:1, foo4:4, foo2:2, foo5:5, foo3:3}

on convertDictToMap(aDict)
  set aMapTable to current application’s NSMapTable’s mapTableWithKeyOptions:(current application’s NSMapTableStrongMemory) valueOptions:(current application’s NSMapTableStrongMemory)
  
  set keyList to aDict’s allKeys() as list
  
set valList to aDict’s allValues() as list
  
set aLen to length of keyList
  
  repeat with i from 1 to aLen
    set aKey to contents of item i of keyList
    
set aVal to contents of item i of valList
    (
aMapTable’s setObject:aVal forKey:aKey)
  end repeat
  
  return aMapTable
end convertDictToMap

★Click Here to Open This Script 

recordから直接NSMapTableに変換するものも作っておきました。

AppleScript名:NSMapTableのじっけん(record to NSMapTable)
– Created 2017-01-02 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aRec to {foo1:1, foo2:2, foo3:3, foo4:4, foo5:5}
set aMap to convertRecToMap(aRec) of me
(*
–>  (NSConcreteMapTable) NSMapTable {
[1] foo2 -> 2
[5] foo4 -> 4
[7] foo5 -> 5
[11] foo3 -> 3
[14] foo1 -> 1
}
*)

–Verify
set bDict to aMap’s dictionaryRepresentation() as record
–>  {foo1:1, foo4:4, foo2:2, foo5:5, foo3:3}

on convertRecToMap(aRec as record)
  set aDict to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aMapTable to current application’s NSMapTable’s mapTableWithKeyOptions:(current application’s NSMapTableStrongMemory) valueOptions:(current application’s NSMapTableStrongMemory)
  
  
set keyList to aDict’s allKeys() as list
  
set valList to aDict’s allValues() as list
  
set aLen to length of keyList
  
  
repeat with i from 1 to aLen
    set aKey to contents of item i of keyList
    
set aVal to contents of item i of valList
    (
aMapTable’s setObject:aVal forKey:aKey)
  end repeat
  
  
return aMapTable
end convertRecToMap

★Click Here to Open This Script