Archive for the 'NSURL' Category

2017/05/15 感情推定(極性判定) v2

apitoreのREST API「感情推定(極性判定) v2」を呼び出すAppleScriptです。

400文字以下のテキストを解析して、極性(感情)を判定します。ただし、文章が短すぎると判定しづらくなる傾向があるようです。これまでの感情推定APIではpositive/negativeとして判定する傾向があったため、このv2 APIではneutralとして判定する幅を広めにとってもらいました。

本Scriptをテストするためには、apitoreにサインアップしてAccess Tokenを取得し、Script末尾の伏字部分にコピー&ペーストしてください(掲載リストをそのまま実行してもエラーになります)。

AppleScript名:感情推定(極性判定) v2
– Created 2017-05-15 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4639

set aString to "このePubの考え方にそぐわない文章要素がいろいろある。代表的なものは「表」だ。データを掲載しておくのに、「表」は便利な存在だ。書く方からしても、いちいち長々とした文章で説明しなくていいし、読む方からしても整理された情報を読めるわけで、とくにお年寄りに好まれる。ところが、この「表」がePubの出版物にそぐわない。表の幅は変わってほしくないし、文字サイズが大きくなって数ページにわたって表示されるといったことは好ましくない。"
set a1Res to getSentimentFromString(aString) of me
–>  "positive"(なのか?)

on getSentimentFromString(aString)
  set reqURLStr to "https://api.apitore.com/api/39/sentiment-v2/predict"
  
set accessToken to retAccessToken() of me
  
set aRec to {access_token:accessToken, |text|:aString}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
  
set aRESCode to (responseCode of aRes) as integer
  
if aRESCode is not equal to 200 then return false
  
  
set aRESTres to ((json of aRes)’s valueForKeyPath:"predict.sentiment") as string
  
return aRESTres
end getSentimentFromString

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

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 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

on retAccessToken()
  return "xxXXXxxX-XxXx-XXXX-xXXX-XXxXXxxXxxXx" –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2017/05/06 Bing Web Search APIでWebキーワード検索

MicrosoftのBing Web Search APIを呼び出してWebのキーワード検索を行うAppleScriptです。

Microsoft Cognitive Servicesのサイトで、開発者アカウント登録を行えば、本APIについては1か月に1,000回まで無料で使用できます(1秒間に7回までという制限もあります)。

アカウント登録を行い、Bing Web SearchをEnableに設定して、本AppleScriptの末尾のretAPIKey()ハンドラ内にAPI Key 1を入力してください(API Keyを記入したScriptを決してそのまま第三者に配布しないでください。あくまでテストと確認用です)。

個人的にBingは検索エンジンとして常用していません。Google検索にくらべて見つかる情報量が少ないと実感していることがその理由です。そのため、Bingの検索エンジンを呼び出せてもあまりメリットを見出せないところ。あくまで実験の一環です。

AppleScript名:Bing Web Search APIでWebキーワード検索
– Created 2017-05-03 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4634

set aStr to “戦場の絆”

set reqURLStr to “https://api.cognitive.microsoft.com/bing/v5.0/search” –Microsoft Project Oxford
set myAPIkey to retAPIkey() of me –API Primary Key

set aRec to {q:aStr, |count|:“5″, |offset|:“0″, mkt:“ja-JP”}
set bURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPI(bURL, myAPIkey) of me
set aRESTres to json of aRes
set aRESCode to responseCode of aRes
set aRESHeader to responseHeader of aRes

return (webPages of aRESTres)

–POST methodのREST APIを画像をアップロードしつつ呼ぶ
on callRestGETAPI(aURL, anAPIkey)
  –Request
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:anAPIkey forHTTPHeaderField:“Ocp-Apim-Subscription-Key”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
if dRes = missing value then
    set resCode to -1
    
set resHeaders to {}
  else
    set resCode to (dRes’s statusCode()) as integer
    
–Get Response Header
    
set resHeaders to (dRes’s allHeaderFields()) as record
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPI

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 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

on retAPIkey()
  return “XxXxXXxXxXxXXxXXxXXXxXXXxxxxXxxX” –API Key 1
end retAPIkey

★Click Here to Open This Script 

2017/05/04 Analyze Imageで画像認識

MicrosoftのCognitive ServicesのREST APIのひとつ、Computer Vision APIの「Analyze Image」を呼び出して画像認識するAppleScriptです。

Microsoft Cognitive Servicesのサイトで、開発者アカウント登録を行えば、本APIについては1か月に5,000回まで無料で使用できます(1分間に20回までという制限もあります)。

アカウント登録を行い、Analyze ImageをEnableに設定して、本AppleScriptの末尾のretAPIKey()ハンドラ内にAPI Key 1を入力してください(API Keyを記入したScriptを決してそのまま第三者に配布しないでください。あくまでテストと確認用です)。

指定した画像のカテゴリ(Categories)、タグ情報(Tags)、詳細内容(Description)の情報を取得しています。

精度については、実際にテスト画像と得られた認識データを見比べていただくしかありません。カタツムリとか誕生日ケーキとか夕日や花火、ワインボトルなど(!)、驚くほど正確に認識されています。夕日の手前にあるのは飛行機ではないのですが、そのぐらいの誤差はあります(イルカを「犬」と判定されたりもしました)。

ためしに、この結果(Description)をそのままGoogle Tlanstlate APIに渡して日本語訳させ画像のFinderコメント欄に入れる実験などもやってみたところ、面白い結果が得られました(実用性はまだまだですが、言いたいことはわかる、というレベル。個人的には英語のままのほうがわかりやすいかも)。

こうしたサービスを利用して、写真.app(Photos.app)内の写真にすべてタグ付けして、タグをもとに風景の写真だけを新規アルバムに入れて分類するといった使い方はできそうです(すでにやってるし)。そして、AppleのアプリケーションとMicrosoftやGoogleのWebサービスを連携させるといった使い方はAppleが提供するわけがないので、こういう用途こそAppleScriptで勝手に連携させるべきだと思います。

r0010704_resized.png
{{metadata:{width:2592, |format|:”Jpeg”, height:1944}, tags:{{|name|:”fireworks”, confidence:0.998994648457}, {|name|:”outdoor object”, confidence:0.998748064041}}, categories:{{|name|:”dark_fireworks”, score:0.99609375}}, |description|:{tags:{”fireworks”, “object”}, captions:{{|text|:“a close up of fireworks”, confidence:0.233880494749}}}, requestId:”ce5e5c15-f68f-4647-9694-5fb8ede9cd31″}}

r0015213_resized.png
{{metadata:{width:2592, |format|:”Jpeg”, height:1944}, tags:{{|name|:”ground”, confidence:0.999917149544}, {|name|:”animal”, confidence:0.993541717529}, {|name|:”invertebrate”, hint:”animal”, confidence:0.952201843262}, {|name|:”outdoor”, confidence:0.887740492821}, {|name|:”mollusk”, hint:”animal”, confidence:0.814713895321}, {|name|:”snail”, hint:”animal”, confidence:0.649717211723}}, categories:{{|name|:”abstract_texture”, score:0.6015625}}, |description|:{tags:{”animal”, “outdoor”, “shellfish”, “snail”, “piece”, “laying”, “food”, “sitting”, “top”, “surface”, “lying”, “banana”, “close”, “fruit”, “bird”, “beach”, “plate”, “board”, “street”}, captions:{{|text|:“a snail on the ground”, confidence:0.480042590526}}}, requestId:”b290dc83-0e33-41b0-8a39-76c067bcffb8″}}

r0015918_resized.png
{{metadata:{width:2048, |format|:”Jpeg”, height:1536}, tags:{{|name|:”grass”, confidence:0.99923813343}, {|name|:”outdoor”, confidence:0.997150361538}, {|name|:”ground”, confidence:0.972813665867}, {|name|:”standing”, confidence:0.93672734499}, {|name|:”animal”, confidence:0.917161226273}, {|name|:”bird”, confidence:0.824012756348}}, categories:{{|name|:”animal_horse”, score:0.98046875}}, |description|:{tags:{”grass”, “outdoor”, “standing”, “bird”, “animal”, “water”, “field”, “white”, “small”, “walking”, “front”, “sitting”, “parrot”, “brown”, “large”, “grassy”, “green”, “body”, “dirt”, “red”, “river”}, captions:{{|text|:“a bird that is standing in the grass”, confidence:0.859258793309}}}, requestId:”bc5b8778-cf96-4d3c-8ba9-be22b38c36dd”}}

img_2502_resized.png
{{metadata:{width:3264, |format|:”Jpeg”, height:2448}, tags:{{|name|:”sky”, confidence:0.999066531658}, {|name|:”outdoor”, confidence:0.99786490202}, {|name|:”sunset”, confidence:0.880310297012}, {|name|:”distance”, confidence:0.229086950421}}, categories:{{|name|:”outdoor_”, score:0.0078125}, {|name|:”outdoor_waterside”, score:0.5234375}}, |description|:{tags:{”outdoor”, “sunset”, “airplane”, “plane”, “sitting”, “building”, “runway”, “large”, “front”, “water”, “pier”, “top”, “sun”, “track”, “orange”, “light”, “road”, “bridge”, “standing”, “train”, “man”, “jet”, “white”, “city”, “riding”, “red”, “flying”, “bird”, “blue”, “night”, “river”, “tower”, “tarmac”}, captions:{{|text|:“a plane that is in front of a sunset”, confidence:0.493561860724}}}, requestId:”49705b7d-99cb-4234-9af6-b30a32f02ad5″}}

img_0313_resized.png
{{metadata:{width:4032, |format|:”Jpeg”, height:3024}, tags:{{|name|:”indoor”, confidence:0.929384291172}, {|name|:”candle”, confidence:0.877458691597}, {|name|:”birthday”, confidence:0.817751348019}, {|name|:”lit”, confidence:0.53784763813}}, categories:{{|name|:”others_”, score:0.01171875}}, |description|:{tags:{”table”, “indoor”, “cake”, “birthday”, “food”, “sitting”, “lit”, “plate”, “front”, “small”, “top”, “bowl”, “fruit”, “filled”, “chocolate”, “holding”, “man”, “woman”}, captions:{{|text|:“a birthday cake with lit candles”, confidence:0.8700279282}}}, requestId:”62b58a19-2d3a-4f9a-bd54-5aa4460d8385″}}

img_2187_resized.png
{{metadata:{width:3264, format:”Jpeg”, height:2448}, tags:{{name:”bottle”, confidence:0.999316096306}, {name:”table”, confidence:0.987863183022}, {name:”indoor”, confidence:0.968602716923}, {name:”wine”, confidence:0.928377449512}, {name:”alcohol”, confidence:0.846504926682}, {name:”food”, confidence:0.785823404789}, {name:”glass”, confidence:0.782037138939}, {name:”beverage”, confidence:0.776733756065}}, categories:{{name:”drink_”, score:0.90234375}}, description:{tags:{”bottle”, “table”, “indoor”, “wine”, “sitting”, “alcohol”, “food”, “glass”, “beverage”, “cup”, “banana”, “empty”, “top”, “sandwich”, “counter”, “beer”, “phone”, “orange”, “wooden”, “computer”, “laying”}, captions:{{text:“a bottle of wine”, confidence:0.858091829408}}}, requestId:”d2db3a05-fcb0-43bb-8191-89707904918a”}}

r0020016_resized.png
{{metadata:{width:1280, format:”Jpeg”, height:960}, tags:{{name:”sky”, confidence:0.999883055687}, {name:”outdoor”, confidence:0.997511506081}, {name:”person”, confidence:0.910886585712}, {name:”toy”, confidence:0.878364562988}}, categories:{{name:”others_”, score:0.00390625}, {name:”outdoor_”, score:0.01171875}}, description:{tags:{”outdoor”, “person”, “toy”, “thing”, “man”, “white”, “grass”, “standing”, “people”, “field”, “riding”, “jumping”, “doing”, “air”, “holding”, “group”, “trick”, “board”, “statue”, “dog”, “player”, “ramp”}, captions:{{text:“a statue of a man jumping in the air”, confidence:0.153422169506}}}, requestId:”ec5dc466-76c5-47df-b858-2e418ce891a8″}}

r0016164_resized.png
{{metadata:{width:2048, format:”Jpeg”, height:1536}, tags:{{name:”water”, confidence:0.999519586563}, {name:”animal”, confidence:0.993490874767}, {name:”outdoor”, confidence:0.992024421692}, {name:”aquatic mammal”, hint:”animal”, confidence:0.978799343109}, {name:”mammal”, hint:”animal”, confidence:0.914148926735}, {name:”ocean”, confidence:0.804374277592}, {name:”whale”, hint:”animal”, confidence:0.533892810345}, {name:”wave”, confidence:0.527211129665}, {name:”dolphin”, hint:”animal”, confidence:0.340564578772}}, categories:{{name:”outdoor_”, score:0.00390625}}, description:{tags:{”water”, “animal”, “outdoor”, “mammal”, “ocean”, “wave”, “laying”, “brown”, “riding”, “surfing”, “top”, “body”, “lying”, “board”, “large”, “beach”, “floating”, “swimming”, “standing”, “dog”, “young”, “white”, “man”}, captions:{{text:“a dog swimming in the ocean”, confidence:0.604725984086}}}, requestId:”161b6c0f-f3fd-4e06-b4be-d5baa9516e53″}}

AppleScript名:Analyze Image APIで画像認識
– Created 2017-05-03 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4625

set imgFilePath to POSIX path of (choose file of type {“public.jpeg”} with prompt “Select an Image to Analyze”)
set aRes to recogImage(imgFilePath) of me

on recogImage(imgFilePath)
  set reqURLStr to “https://api.projectoxford.ai/vision/v1.0/analyze”
  
set myAPIkey to retAPIkey() of me –API Key 1
  
  
set aRec to {visualFeatures:“Categories,Tags,Description”, details:“Celebrities”, language:“en”}
  
set bURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestPOSTAPIAndParseResultsWithImage(bURL, imgFilePath, myAPIkey) of me
  
set aRESTres to json of aRes
  
set aRESCode to responseCode of aRes
  
set aRESHeader to responseHeader of aRes
  
  
return (aRESTres as list)
end recogImage

–POST methodのREST APIを画像をアップロードしつつ呼ぶ
on callRestPOSTAPIAndParseResultsWithImage(aURL, imgFilePath, myAPIkey)
  –Get Image Contents from file
  
set imgPathStr to current application’s NSString’s stringWithString:imgFilePath
  
set imgData to current application’s NSData’s dataWithContentsOfFile:imgPathStr
  
set postBody to current application’s NSMutableData’s |data|()
  
postBody’s appendData:imgData
  
  
–Request
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setHTTPBody:postBody
  
aRequest’s setValue:“application/octet-stream” forHTTPHeaderField:“Content-Type”
  
aRequest’s setValue:myAPIkey forHTTPHeaderField:“Ocp-Apim-Subscription-Key”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
if dRes = missing value then
    set resCode to -1
    
set resHeaders to {}
  else
    set resCode to (dRes’s statusCode()) as integer
    
–Get Response Header
    
set resHeaders to (dRes’s allHeaderFields()) as record
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPOSTAPIAndParseResultsWithImage

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 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())
  
  
return aURL
end retURLwithParams

on retAPIkey()
  return “xXXxXXXXxXXxXXXxXXXXXXXXxXXXXXXx” –API Key 1
end retAPIkey

★Click Here to Open This Script 

2017/04/30 Computer Vision APIで文字認識(OCR)

MicrosoftのCognitive ServicesのREST APIのひとつ、Computer Vision APIを呼び出すAppleScriptです。

MicrosoftのAPIは割とシンプルでオンラインドキュメントも読みやすいため、書くのに3分ぐらいしかかかっていません(既存の別のAPI用のものをend pointとAPI keyとパラメータを書き換えただけ)。

Microsoft Cognitive Servicesのサイトで、開発者アカウント登録を行えば、本APIについては1か月に5,000回まで無料で使用できます(1分間に20回までという制限もあります)。アカウント登録を行い、OCR ServiceをEnableに設定して、本AppleScriptの末尾のretAPIKey()ハンドラ内にAPI Key 1を入力してください(API Keyを記入したScriptを決してそのまま第三者に配布しないでください。あくまでテストと確認用です)。

cognitive_key.png
▲ここの「Key 1」

Vision APIでは、対応画像ファイル形式はJPEG、PNG、GIF、BMP(!)。ファイル容量は4MB以下、50×50ピクセル以上の大きさである必要があります。

img_0320_resized.png

こんな「戦場の絆」のリプレイIDをゲームセンターで撮影して、このIDをもとにYouTubeのリプレイムービーのURLを検索することになるわけですが、このリプレイIDのOCRにComputer Vision APIを使ってみました。

この用途(ランダムに近い英数字の固定桁の組み合わせ、画面上のイメージの認識)については、かなり使える印象です。認識用に使用した画像は、iPhone 7で撮影して写真.appにiCloud経由で転送された写真をそのまま利用しており、ファイルサイズは2.6MB、画像の大きさは4032×3024ピクセルありました。このぐらいだと、認識のためにMicrosoftのクラウドにアップロードするのに少々待たされます。

{boundingBox:”929,1171,746,134″, text:”fy57nt2f“}
{boundingBox:”920,1438,770,135″, text:”3kt5y72v“}

この用途においては、とても誤認識が少ないと感じています。本来取り出したい目的のデータが日本語(ja)ではないので、言語を英数字(en)に指定して呼び出しています。

縦書きの日本語の印刷物の認識だと、もう少し結果が異なってくると思います。一応、この画面についても当初は日本語(ja)で認識していましたが、書体の問題もあり(ちょっと太すぎ?)日本語の文字については誤認識されまくっていました。

AppleScript名:Computer Vision APIで文字認識(OCR)
– Created 2017-04-30 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4622

set imgFilePath to POSIX path of (choose file of type {“public.image”} with prompt “Select an Image to OCR”)

set reqURLStr to “https://api.projectoxford.ai/vision/v1.0/ocr” –Microsoft Cognitive Services OCR endpoint
set myAPIkey to retAPIkey() of me –API Primary Key

–Request parameters
set aRec to {|language|:“en”, detectOrientation:“true”}
set bURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestPOSTAPIAndParseResultsWithImage(bURL, myAPIkey, imgFilePath) of me
set aRESTres to json of aRes

set aRESCode to responseCode of aRes
if aRESCode is not equal to 200 then return false
set aRESHeader to responseHeader of aRes

return ((regions of aRESTres) as list)
–>  {{language:”en”, regions:{{boundingBox:”728,366,1497,2042″, lines:{{boundingBox:”1655,366,186,28″, words:{{boundingBox:”1655,366,186,28″, text:”pea-a-r”}}}, {boundingBox:”1223,962,467,89″, words:{{boundingBox:”1223,962,467,89″, text:”UäLCOD”}}}, {boundingBox:”753,1134,922,171″, words:{{boundingBox:”753,1134,64,156″, text:”1″}, {boundingBox:”929,1171,746,134″, text:”fy57nt2f”}}}, {boundingBox:”1761,1167,458,64″, words:{{boundingBox:”1761,1175,80,53″, text:”20″}, {boundingBox:”1862,1169,169,62″, text:”17/0″}, {boundingBox:”2045,1167,174,60″, text:”4/26″}}}, {boundingBox:”2005,1231,215,52″, words:{{boundingBox:”2005,1231,215,52″, text:”17:55″}}}, {boundingBox:”742,1403,948,170″, words:{{boundingBox:”742,1403,86,160″, text:”2″}, {boundingBox:”920,1438,770,135″, text:”3kt5y72v”}}}, {boundingBox:”1765,1432,459,65″, words:{{boundingBox:”1765,1441,81,53″, text:”20″}, {boundingBox:”1866,1434,170,63″, text:”17/0″}, {boundingBox:”2050,1432,174,61″, text:”4/26″}}}, {boundingBox:”2010,1495,215,54″, words:{{boundingBox:”2010,1495,215,54″, text:”17:47″}}}, {boundingBox:”736,1672,88,176″, words:{{boundingBox:”736,1672,88,176″, text:”3″}}}, {boundingBox:”728,2240,96,168″, words:{{boundingBox:”728,2240,96,168″, text:”5″}}}}}, {boundingBox:”2817,1217,186,320″, lines:{{boundingBox:”2817,1217,175,53″, words:{{boundingBox:”2817,1217,175,53″, text:”6vs6″}}}, {boundingBox:”2826,1483,177,54″, words:{{boundingBox:”2826,1483,177,54″, text:”6vs6″}}}}}}, textAngle:0.0, orientation:”Up”}}

–POST methodのREST APIを画像をアップロードしつつ呼ぶ
on callRestPOSTAPIAndParseResultsWithImage(aURL, anAPIkey, imgFilePath)
  
  
–Get Image Contents from file
  
set imgPathStr to current application’s NSString’s stringWithString:imgFilePath
  
set imgData to current application’s NSData’s dataWithContentsOfFile:imgPathStr
  
set postBody to current application’s NSMutableData’s |data|()
  
postBody’s appendData:imgData
  
  
–Request
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setHTTPBody:postBody
  
aRequest’s setValue:“application/octet-stream” forHTTPHeaderField:“Content-Type”
  
aRequest’s setValue:anAPIkey forHTTPHeaderField:“Ocp-Apim-Subscription-Key”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to (dRes’s statusCode()) as integer
  
  
–Get Response Header
  
set resHeaders to (dRes’s allHeaderFields()) as record
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestPOSTAPIAndParseResultsWithImage

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 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

on retAPIkey()
  return “xXXXXxXxXxXXXXxxxXXxXXXxxXxxXxxx” –API Primary Key
end retAPIkey

★Click Here to Open This Script 

2017/04/27 テックサイト ごちゃまぜフィードを呼び出す

apitoreREST API「テックサイト ごちゃまぜフィード」を呼び出すAppleScriptです。

apitore側で、以下のテック系Blogを自動巡回して(30分に一度)更新情報を蓄積、新しい順番にソートしたものがREST API経由で提供されています。

巡回サイトは、ライフハッカー、メディア・パブ、スラッシュドット、ギズモード、ゆかしメディア、TechWave、TechDoll.jp、TechCrunch、Reuters、Google Japan Blog、GIGAZINE、Engadget、CNET、All About(オールアバウト) [新着記事]、男子ハック、Techable、ReadWrite Japan、MdN Design Interactive、WIRED.jp、アンドロイドアプリが見つかる!スマホ情報ならオクトバ、ITmedia 総合、ITmedia トップストーリー

となっています(記事執筆時)。

apitoreでは、この「テックサイト ごちゃまぜフィード」のほか、「旅行系」「ニュース」「ブログ 」「デザイン系」などの情報源のフィード系REST APIを提供しています。

本Scriptをテストするためには、apitoreにサインアップしてAccess Tokenを取得して、Script末尾の伏字部分にコピー&ペーストしてください(掲載リストをそのまま実行してもエラーになります)。

Webクローラーを自前で作って定期実行しなくても、Web API経由でクローリングした結果がもらえるというのは、とてもメリットが大きいと思います。AppleScriptではGUIアプリケーションの内部機能からOS内部のCocoa API、shell script、そしてWeb上のREST APIまで直接呼べるので、こんな「なんでもアリ」な環境はなかなかないでしょう。

AppleScript名:テックサイト ごちゃまぜフィード
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4616

set allFeeds to {}

repeat with i from 1 to 100
  set {aRes, maxNum} to getAFeeds(i) of me
  
  
if aRes = false then exit repeat
  
set maxNum to maxNum as number
  
set allFeeds to allFeeds & aRes
  
if (maxNum div 10) i then
    exit repeat
  end if
end repeat

return allFeeds
–>  
(*
{{author:”Ittousai”, sourceTitle:”Engadget Japanese RSS Feed”, title:” 速報:サムスンGalaxy S8発表イベント UNPACKED 2017 (ライブ更新ページ)
“, link:”http://japanese.engadget.com/2017/03/29/galaxy-s8-unpacked-2017/”, pubDate:1.49079606E+12, description:”

“, sourceLink:”http://japanese.engadget.com/rss.xml”},
*)

on getAFeeds(aNum)
  set reqURLStr to “https://api.apitore.com/api/35/feeds/tech”
  
set accessToken to retAccessToken() —Access Token
  
set aRec to {access_token:accessToken, page:(aNum as string)}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
  
set aRESCode to (responseCode of aRes) as integer
  
if aRESCode is not equal to 200 then return {false, false}
  
  
set aRESTres to (json of aRes) as record
  
  
set sentiRes to entries of aRESTres
  
set allNum to num of aRESTres
  
log allNum
  
  
return {sentiRes, allNum}
end getAFeeds

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

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 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

on retAccessToken()
  return “XXXXxxxX-xxxx-XXXx-xxxX-XxxxXxXxxXXx” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2017/03/31 簡単ツイート収集_search

Apitoreの「簡単ツイート収集」REST APIを呼び出して、指定キーワードによるTweet内容の検索を行うAppleScriptです。

実行前にApitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

また、Twitterのサービスとの連携をオンにするために、Apitoreのマイページから「Twitterと連携する」をクリックし、ApitoreをTwitterとアプリ連携してください。

AppleScript名:簡単ツイート収集_search
– Created 2017-03-29 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4572

set aQuery to “#07Itakura”
set aResList to twitterSearchByQuery(aQuery) of me
–> {tweets:{{sentiment:missing value, favoritedCount:409, source:”Echofon“, retweetCount:392, userId:371790917, userName:”機動戦士ガンダム第07板倉小隊”, userScreenName:”07itakura”, text:”【お知らせ】本日放送した板倉小隊特番のアーカイブを明日26日の昼12時から板倉小隊のHPにて1ヵ月限定で配信決定!見逃してしまった方、もう一度見たいという方、ぜひお楽しみに! https://t.co/Q9q6VhiNGU #07itakura”, statusId:8.45606316664021E+17, sentimentScore:missing value, retweeted:false, favorited:false, createdAt:1.490443231E+12, userProfileImageURL:”http://pbs.twimg.com/profile_images/2578804231/hmzlhl1aaxaen8nf8i5b_normal.png”},….

on twitterSearchByQuery(aQuery)
  set reqURLStr to “https://api.apitore.com/api/23/twitter/search”
  
set accessToken to retAccessToken() —Access Token
  
set aRec to {access_token:accessToken, q:aQuery, sinceId:“-1″, maxId:“-1″, iter:“1″}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL) of me
  
set aRESCode to (responseCode of aRes) as integer
  
set aRESTres to (json of aRes) as record
  
  
return aRESTres
end twitterSearchByQuery

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

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 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

on retAccessToken()
  return “XXXXxxxX-xxxx-XXXx-xxxX-XxxxXxXxxXXx” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2017/03/15 Spotlightで指定フォルダ以下の指定文字を含むファイル一覧を取得

Cocoaの機能を呼び出すAppleScriptObjCでは、さまざまなCocoaのAPIを呼び出す手法が模索されてきました。その中でもSpotlight検索は「割とまだ決定版の手法が確立していない」ものでありました。

spotlightでタグを指定して検索
http://piyocast.com/as/archives/3731

ASOCでmdfindするじっけん v4(フルパスを返す)
http://piyocast.com/as/archives/4122

などなど、徐々に進化してきて、Shane StanleyのAppleScript Libraries「BridgePlus」にSpotlightの呼び出し命令が実装されたりと、手段が洗練されてきたという経緯があります。

書籍「AppleScript 10大最新技術」にも掲載していますが、その時点のバージョンよりもはるかにこなれた書き方がML上でShane Stanleyから提示されました。いままでよりもはるかに短いので、ちょっと腰を抜かしてしまったほど。しかも、とてもさりげなく、、、

「ああ、こういう書き方でもいいんだ、、、」

と、かなりすごいことになっています。

AppleScript名:Spotlightで指定フォルダ以下の指定文字を含むファイル一覧を取得
– Created 2017-03-15 By Shane Stanley
use AppleScript version “2.4″ – Yosemite (10.10) or later
use framework “Foundation”
use scripting additions
–http://piyocast.com/as/archives/4528

set thePath to POSIX path of (path to desktop) – whatever

–ファイル名で検索
set theKeyword to “スクリーンショット”
set fResList to my searchPath:thePath searchPredicate:“(kMDItemFSName CONTAINS [c]%@)” predicateArgs:{theKeyword}
–>  {”/Users/me/Desktop/2013/03/スクリーンショット 2016-12-15 8.44.28.png”, “/Users/me/Desktop/FromDesktop/samples/list splitted or broken/スクリーンショット 2015-08-31 10.49.30.png”, …… }

–UTI(File Kind)で検索
set theKeyword to “public.png”
set fResList to my searchPath:thePath searchPredicate:“(kMDItemContentType == [c]%@)” predicateArgs:{theKeyword}
–> {”/Users/me/Desktop/2013/03/スクリーンショット 2016-12-15 8.44.28.png”, “/Users/me/Desktop/FromDesktop/IMG_3143_resized.png”, “/Users/me/Desktop/FromDesktop/asoctable.png”….}

–ファイルの内容で検索
set fResList to my searchPath:thePath searchPredicate:“(kMDItemTextContent == [c]%@)” predicateArgs:{“戦場の絆”}
–>  {”/Users/me/Desktop/2013/01/gundam_games_history.txt”, “/Users/me/Desktop/book1_2.0.pdf”}

on searchPath:thePath searchPredicate:predString predicateArgs:argList
  set thePred to current application’s NSPredicate’s predicateWithFormat:predString argumentArray:argList
  
set targetURL to current application’s |NSURL|’s fileURLWithPath:thePath
  
set theQuery to current application’s NSMetadataQuery’s new()
  
  
theQuery’s setPredicate:thePred
  
theQuery’s setSearchScopes:{targetURL}
  
theQuery’s startQuery()
  
  
repeat while theQuery’s isGathering() as boolean
    delay “0.001″ as real
  end repeat
  
theQuery’s stopQuery()
  
  
set theCount to theQuery’s resultCount()
  
set theResults to current application’s NSMutableArray’s array()
  
  
repeat with i from 1 to theCount
    set aResult to (theQuery’s resultAtIndex:(i - 1))
    
set thePath to (aResult’s valueForAttribute:(current application’s NSMetadataItemPathKey))
    (
theResults’s addObject:thePath)
  end repeat
  
  
return (theResults’s sortedArrayUsingSelector:“compare:”) as list
end searchPath:searchPredicate:predicateArgs:

★Click Here to Open This Script 

2017/02/14 指定バンドルIDのアプリケーションのアイコンへのパスを求める

指定バンドルIDのアプリケーションのアイコンへのパスを求めるAppleScriptです。

とりあえず、ループで各バンドルIDに該当するアプリアイコンをダイアログ表示します。

bbe.png

twa.png

find.png

AppleScript名:指定バンドルIDのアプリケーションのアイコンへのパスを求める
– Created 2017-02-14 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/4460

set iconList to {“com.barebones.bbedit”, “com.barebones.textwrangler”, “com.apple.Finder”}
repeat with i in iconList
  set aPath to retIconPath(i) of me
  
if aPath is not equal to false then
    display dialog “ICNS test” with title i with icon ((POSIX file aPath) as alias) buttons {“OK”} default button 1
  end if
end repeat

–指定バンドルIDのアプリケーションのアイコンのフルパスを取得する
on retIconPath(anID)
  set aRes to chkAppIsInstalled(anID) of me
  
if aRes = false then return false
  
set appPathPOSIX to (current application’s NSWorkspace’s sharedWorkspace()’s absolutePathForAppBundleWithIdentifier:anID) as string
  
set anIconPath to getIconFilePath(appPathPOSIX) of me
  
return anIconPath
end retIconPath

–指定バンドルIDのアプリケーションが存在しているかチェック
on chkAppIsInstalled(aBundleID as string)
  set aRes to current application’s NSWorkspace’s sharedWorkspace()’s URLForApplicationWithBundleIdentifier:aBundleID
  
set bRes to (aRes is not equal to missing value)
  
return bRes
end chkAppIsInstalled

–指定ファイルのアイコンのファイルのパスを取得する
on getIconFilePath(aPOSIXPath)
  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
  
return ifonFileFullPath
end getIconFilePath

★Click Here to Open This Script 

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/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/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/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/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 

2016/12/09 gooの形態素解析APIを呼び出す

gooラボが公開している各種APIのうちの、形態素解析APIを呼び出して日本語をparseするAppleScriptです。


supported by goo

利用にあたっては、gooラボAPI利用方法のページからのリンクで、Githubのアカウントを用いて(先に、Githubのアカウントを取得してある必要がある)ひもづけして(リンクをクリックするとひもづけ完了)、Application IDを取得。取得したIDをScript中に記入しておく必要があります。

gooのAPIは見た限りではみんなPOST methodを使って情報をAPIに受け渡す必要があり、少々クセがあります。ただし1つ攻略できてしまえば全部攻略できたも同じ。難易度はそれほど高くはありません(全API攻略済み)。

gooが提供しているAPIの機能レベルについては「他より頑張っている」印象。

 キーワード抽出API:面白いけど、固有名詞辞書の内容次第

 ひらがな化API:ただしい「読み」のひらがなにできるかは固有名詞辞書次第

 固有表現抽出API:

 語句類似度算出API:ウィンドウズとWindows程度の類似度は分かるが、実際に関連性がありそうな単語同士の関連性がそれほど高く評価されない。Apitoreの「単語ベクトル変換【新語対応】」(word2vec)の方が使える印象

 時刻情報正規化API:10年以上前にAppleScriptで作った気がする。ただ、こうして提供されているのは便利だし意義深い

 商品評判要約API:実用性の高そうな要約エンジンは必要。どの程度の長文の要約に耐えられるかがみどころ。実用性は未知数

当の形態素解析APIについては、Webサービスの常で、イレギュラーな人名などの固有名詞を正確に認識することは困難なようです。逆に、Yahoo!の形態素解析辞書に「長野谷」という名前が登録されていること自体が異例といえるでしょう。

AppleScript名:Gooの形態素解析APIを呼び出す
– Created 2016-12-08 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–https://labs.goo.ne.jp/api/jp/morphological-analysis/
–http://piyocast.com/as/archives/4354

set anID to retAPIKey() of me

set reqURLStr to “https://labs.goo.ne.jp/api/morph”
set aPostData to {request_id:“record001″, sentence:“私の名前は長野谷です。”, app_id:anID}
set aRes to callRestPOSTAPIAndParseResults(reqURLStr, aPostData) of me
set aRESCode to (responseCode of aRes) as integer
if aRESCode is not equal to 200 then return false

set aRESHeader to responseHeader of aRes
set aRESTres to json of aRes
–>  (NSDictionary) {request_id:”record001″, word_list:{{{”私”, “名詞”, “ワタシ”}, {”の”, “格助詞”, “ノ”}, {”名前”, “名詞”, “ナマエ”}, {”は”, “連用助詞”, “ハ”}, {”長野”, “名詞”, “ナガノ”}, {”谷”, “名詞接尾辞”, “ダニ”}, {”です”, “判定詞”, “デス”}, {”。”, “句点”, “$”}}}}

–POST methodのREST APIを呼ぶ
on callRestPOSTAPIAndParseResults(aURL, aPostData)
  set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aPostData options:0 |error|:(missing value)
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setHTTPBody:dataJson
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Content-Type”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestPOSTAPIAndParseResults

on retAPIKey()
  return “XXxXXxXXxXxxxXXXxXXxXxXxXXxXxXXXxXxXxxxXxXXXXxXxxXXXxXXXxXXXXxXX” –Goo API Key
end retAPIKey

★Click Here to Open This Script 

2016/12/05 IPIFYで自分のグローバルIPアドレスを取得

ipfy.orgを呼び出して、グローバルIPアドレスを取得するAppleScriptです。

以前に掲載した「自分の(インターネットアクセス時の)IPアドレスを調べる」と同じ働きをするものです。

同じ結果が得られることを確認していますが、こちらの方が高速にアドレスを取得できています。

AppleScript名:IPIFYで自分のグローバルIPアドレスを取得
– Created 2016-12-04 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4343

set reqURLStr to “https://api.ipify.org”
set aRec to {|format|:“json”}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me
set aRESCode to (responseCode of aRes) as integer
if aRESCode is not equal to 200 then error “Server Error”

set aRESHeader to responseHeader of aRes
set aRESTres to |ip| of ((json of aRes) as record)

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“GET”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

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 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/11/30 Livedoorお天気WebサービスAPIで指定地点の天気予報を取得する

livedoorのお天気WebサービスAPIを呼び出して、指定地点コードで指定した地点の天気予報を取得するAppleScriptです。

本サービスを呼び出すのに、開発者登録を行う必要はありません。

例として東京都の東京地方のコード(130010)を指定しています。

現在の緯度・軽度情報を取得して、その情報から住所コードを取得する(逆住所ジオコーディング)と、このようなサービスを利用して「現在位置の天気予報を取得する」という処理ができます。

AppleScript名:Livedoorお天気WebサービスAPIで指定地点の天気予報を取得する
– Created 2016-10-29 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://weather.livedoor.com/weather_hacks/webservice
–http://piyocast.com/as/archives/4337

set reqURLStr to “http://weather.livedoor.com/forecast/webservice/json/v1″

set aRec to {city:“130010″}
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESCode to responseCode of aRes
if aRESCode is not equal to 200 then error “Server Error”

set aRESHeader to responseHeader of aRes

set aRESTres to (json of aRes) as record
return aRESTres
(*
{location:{prefecture:”東京都”, city:”東京”, area:”関東”}, publicTime:”2016-11-30T17:00:00+0900″, title:”東京都 東京 の天気”, copyright:{provider:{{link:”http://tenki.jp/”, |name|:”日本気象協会”}}, title:”(C) LINE Corporation”, image:{height:26, title:”livedoor 天気情報”, width:118, |url|:”http://weather.livedoor.com/img/cmn/livedoor.gif”, link:”http://weather.livedoor.com/”}, link:”http://weather.livedoor.com/”}, link:”http://weather.livedoor.com/area/forecast/130010″, forecasts:{{|date|:”2016-11-30″, dateLabel:”今日”, temperature:{min:missing value, max:missing value}, image:{title:”曇り”, width:50, |url|:”http://weather.livedoor.com/img/icon/8.gif”, height:31}, telop:”曇り”}, {|date|:”2016-12-01″, dateLabel:”明日”, temperature:{min:{celsius:”6″, fahrenheit:”42.8″}, max:{celsius:”14″, fahrenheit:”57.2″}}, image:{title:”曇時々雨”, width:50, |url|:”http://weather.livedoor.com/img/icon/10.gif”, height:31}, telop:”曇時々雨”}, {|date|:”2016-12-02″, dateLabel:”明後日”, temperature:{min:missing value, max:missing value}, image:{title:”晴時々曇”, width:50, |url|:”http://weather.livedoor.com/img/icon/2.gif”, height:31}, telop:”晴時々曇”}}, |description|:{|text|:” 高気圧が三陸沖を東へ移動しています。一方、黄海付近は気圧の谷となっ
ています。

【関東甲信地方】
関東甲信地方は、気圧の谷や湿った空気の影響で曇りとなっています。

30日は、曇りで、気圧の谷や湿った空気の影響で、夜には雨の降る所が
あるでしょう。

12月1日は、気圧の谷の影響により、曇りで、朝にかけて雨の所が多い
見込みです。伊豆諸島では朝にかけて雷を伴う所があるでしょう。

関東近海では、30日から12月1日にかけて波が高いでしょう。船舶は
高波に注意してください。

【東京地方】
30日は、曇りで、夜遅くは雨の降る所があるでしょう。
12月1日は、曇りで、明け方まで雨となる見込みです。”, publicTime:”2016-11-30T16:34:00+0900″}, pinpointLocations:{{link:”http://weather.livedoor.com/area/forecast/1310100″, |name|:”千代田区”}, {link:”http://weather.livedoor.com/area/forecast/1310200″, |name|:”中央区”}, {link:”http://weather.livedoor.com/area/forecast/1310300″, |name|:”港区”}, {link:”http://weather.livedoor.com/area/forecast/1310400″, |name|:”新宿区”}, {link:”http://weather.livedoor.com/area/forecast/1310500″, |name|:”文京区”}, {link:”http://weather.livedoor.com/area/forecast/1310600″, |name|:”台東区”}, {link:”http://weather.livedoor.com/area/forecast/1310700″, |name|:”墨田区”}, {link:”http://weather.livedoor.com/area/forecast/1310800″, |name|:”江東区”}, {link:”http://weather.livedoor.com/area/forecast/1310900″, |name|:”品川区”}, {link:”http://weather.livedoor.com/area/forecast/1311000″, |name|:”目黒区”}, {link:”http://weather.livedoor.com/area/forecast/1311100″, |name|:”大田区”}, {link:”http://weather.livedoor.com/area/forecast/1311200″, |name|:”世田谷区”}, {link:”http://weather.livedoor.com/area/forecast/1311300″, |name|:”渋谷区”}, {link:”http://weather.livedoor.com/area/forecast/1311400″, |name|:”中野区”}, {link:”http://weather.livedoor.com/area/forecast/1311500″, |name|:”杉並区”}, {link:”http://weather.livedoor.com/area/forecast/1311600″, |name|:”豊島区”}, {link:”http://weather.livedoor.com/area/forecast/1311700″, |name|:”北区”}, {link:”http://weather.livedoor.com/area/forecast/1311800″, |name|:”荒川区”}, {link:”http://weather.livedoor.com/area/forecast/1311900″, |name|:”板橋区”}, {link:”http://weather.livedoor.com/area/forecast/1312000″, |name|:”練馬区”}, {link:”http://weather.livedoor.com/area/forecast/1312100″, |name|:”足立区”}, {link:”http://weather.livedoor.com/area/forecast/1312200″, |name|:”葛飾区”}, {link:”http://weather.livedoor.com/area/forecast/1312300″, |name|:”江戸川区”}, {link:”http://weather.livedoor.com/area/forecast/1320100″, |name|:”八王子市”}, {link:”http://weather.livedoor.com/area/forecast/1320200″, |name|:”立川市”}, {link:”http://weather.livedoor.com/area/forecast/1320300″, |name|:”武蔵野市”}, {link:”http://weather.livedoor.com/area/forecast/1320400″, |name|:”三鷹市”}, {link:”http://weather.livedoor.com/area/forecast/1320500″, |name|:”青梅市”}, {link:”http://weather.livedoor.com/area/forecast/1320600″, |name|:”府中市”}, {link:”http://weather.livedoor.com/area/forecast/1320700″, |name|:”昭島市”}, {link:”http://weather.livedoor.com/area/forecast/1320800″, |name|:”調布市”}, {link:”http://weather.livedoor.com/area/forecast/1320900″, |name|:”町田市”}, {link:”http://weather.livedoor.com/area/forecast/1321000″, |name|:”小金井市”}, {link:”http://weather.livedoor.com/area/forecast/1321100″, |name|:”小平市”}, {link:”http://weather.livedoor.com/area/forecast/1321200″, |name|:”日野市”}, {link:”http://weather.livedoor.com/area/forecast/1321300″, |name|:”東村山市”}, {link:”http://weather.livedoor.com/area/forecast/1321400″, |name|:”国分寺市”}, {link:”http://weather.livedoor.com/area/forecast/1321500″, |name|:”国立市”}, {link:”http://weather.livedoor.com/area/forecast/1321800″, |name|:”福生市”}, {link:”http://weather.livedoor.com/area/forecast/1321900″, |name|:”狛江市”}, {link:”http://weather.livedoor.com/area/forecast/1322000″, |name|:”東大和市”}, {link:”http://weather.livedoor.com/area/forecast/1322100″, |name|:”清瀬市”}, {link:”http://weather.livedoor.com/area/forecast/1322200″, |name|:”東久留米市”}, {link:”http://weather.livedoor.com/area/forecast/1322300″, |name|:”武蔵村山市”}, {link:”http://weather.livedoor.com/area/forecast/1322400″, |name|:”多摩市”}, {link:”http://weather.livedoor.com/area/forecast/1322500″, |name|:”稲城市”}, {link:”http://weather.livedoor.com/area/forecast/1322700″, |name|:”羽村市”}, {link:”http://weather.livedoor.com/area/forecast/1322800″, |name|:”あきる野市”}, {link:”http://weather.livedoor.com/area/forecast/1322900″, |name|:”西東京市”}, {link:”http://weather.livedoor.com/area/forecast/1330300″, |name|:”瑞穂町”}, {link:”http://weather.livedoor.com/area/forecast/1330500″, |name|:”日の出町”}, {link:”http://weather.livedoor.com/area/forecast/1330700″, |name|:”檜原村”}, {link:”http://weather.livedoor.com/area/forecast/1330800″, |name|:”奥多摩町”}}}
*)

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

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 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

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

★Click Here to Open This Script 

2016/11/22 Twitterでapplication-only requests認証を行って指定アカウントのタイムラインを取得

Twitterのapplication-only request認証を行なって、指定アカウントのタイムラインを取得するAppleScriptです。

実行前に、Twitterに開発者登録(無料)AppleScriptの登録を行い(My First AppleScriptとかいって)、Consumer KeyとConsumer Secretを取得しておく必要があります(開発者登録を行うには、Twitterアカウントも必要です、ねんのため)。

conskey_conssecret.jpg

自分のConsumer KeyとConsumer SecretをAppleScript中に記入し、実行するとドナルド・トランプ氏の最新のTweetを10件取得します。

application-only request認証は手軽ですが、実行できるAPIの種別に制限があります。投稿を行うには、OAuthによる認証とトークンの取得が必要です。

AppleScript名:Twitterでapplication-only requests認証を行って指定アカウントのタイムラインを取得
– Created 2016-11-22 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4326

set myConsumerKey to “xXXXXXXXxxXXxXxxxXXxXxXXX”
set myConsumerSecret to “xxxxXXXxXxXXXxXXXxxxXXXXXxxXxxXXXxXXXxxXXxxxXXxxXx”

–認証を行って認証済みのBarer Tokenを取得する
set authedToken to getAuthedTokenFromTwitter(myConsumerKey, myConsumerSecret) of me
if authedToken = missing value then return

–実際のAPI呼び出し
set reqURLStr to “https://api.twitter.com/1.1/statuses/user_timeline.json” –URLの前後に空白などが入らないように!!
set bRec to {|count|:“10″, screen_name:“realDonaldTrump”}
set bURL to retURLwithParams(reqURLStr, bRec) of me
set aRes to callRestGETAPIAWithAuth(bURL, authedToken) of me

set aRESCode to responseCode of aRes –Response Code
if aRESCode is not equal to 200 then return false
set aRESHeader to responseHeader of aRes –Response Header

set aRESTres to (json of aRes)
set timeLine to (aRESTres’s valueForKeyPath:“text”) as list
–>  {”Many people would like to see @Nigel_Farage represent Great Britain as their Ambassador to the United States. He would do a great job!”, “Prior to the election it was well known that I have interests in properties all over the world.Only the crooked media makes this a big deal!”, “.@transition2017 update and policy plans for the first 100 days. https://t.co/HTgPXfPWeJ”, “I have always had a good relationship with Chuck Schumer. He is far smarter than Harry R and has the ability to get things done. Good news!”, “General James \”Mad Dog\” Mattis, who is being considered for Secretary of Defense, was very impressive yesterday. A true General’s General!”, “I watched parts of @nbcsnl Saturday Night Live last night. It is a totally one-sided, biased show - nothing funny at all. Equal time for us?”, “Numerous patriots will be coming to Bedminster today as I continue to fill out the various positions necessary to MAKE AMERICA GREAT AGAIN!”, “The cast and producers of Hamilton, which I hear is highly overrated, should immediately apologize to Mike Pence for their terrible behavior”, “The Theater must always be a safe and special place.The cast of Hamilton was very rude last night to a very good man, Mike Pence. Apologize!”, “Our wonderful future V.P. Mike Pence was harassed last night at the theater by the cast of Hamilton, cameras blazing.This should not happen!”}

–Authenticate APIを呼び出して認証を行う
on getAuthedTokenFromTwitter(aConsumerKey, aConsumerSecret)
  set aURL to “https://api.twitter.com/oauth2/token”
  
set barerToken to aConsumerKey & “:” & aConsumerSecret
  
set aStr to current application’s NSString’s stringWithString:barerToken
  
set aData to aStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set bStr to (aData’s base64EncodedStringWithOptions:0) as string
  
set bStr to current application’s NSString’s stringWithString:(“Basic “ & bStr)
  
set aRec to {grant_type:“client_credentials”}
  
set a2URL to retURLwithParams(aURL, aRec) of me
  
  
set a2Res to callRestPOSTAPIWithAuth(a2URL, bStr) of me
  
if (responseCode of a2Res) is not equal to 200 then return
  
set aJSON to (json of a2Res)
  
set authedToken to “Bearer “ & (aJSON’s valueForKey:“access_token”)
  
return authedToken
end getAuthedTokenFromTwitter

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 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

–POST methodのREST APIを呼ぶ(認証つき)
on callRestPOSTAPIWithAuth(aURL, anAPIkey)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:“POST”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
if anAPIkey is not equal to “” then
    aRequest’s setValue:anAPIkey forHTTPHeaderField:“Authorization”
  end if
  
aRequest’s setValue:“gzip” forHTTPHeaderField:“Accept-Encoding”
  
aRequest’s setValue:“application/x-www-form-urlencoded;charset=UTF-8″ forHTTPHeaderField:“Accept”
  
  
–CALL REST API
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
  
–Parse Results
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestPOSTAPIWithAuth

–GET methodのREST APIを呼ぶ(認証つき)
on callRestGETAPIAWithAuth(aURL, anAPIkey)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
if anAPIkey is not equal to “” then
    aRequest’s setValue:anAPIkey forHTTPHeaderField:“Authorization”
  end if
  
aRequest’s setValue:“gzip” forHTTPHeaderField:“Accept-Encoding”
  
aRequest’s setValue:“application/x-www-form-urlencoded;charset=UTF-8″ forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAWithAuth

★Click Here to Open This Script 

2016/11/21 HTMLReaderでWeb上のHTMLからリンクを取得する

オープンソースのフレームワーク「HTMLReader」を用いて、指定のURLのHTMLをダウンロードして指定要素を取り出すAppleScriptです。

実行にあたっては、HTMLReaderをダウンロードしてビルドし、~/Library/Frameworksにインストールしておく必要があります。

AppleScript名:HTMLReaderでWeb上のHTMLからリンクを取得する
– Created 2016-11-21 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “HTMLReader” –https://github.com/nolanw/HTMLReader
–http://piyocast.com/as/archives/4325

set aStr to “https://github.com/nolanw/HTMLReader”
set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
if exRes = false then return –エラー発生時に処理打ち切り

set conType to headerRes’s valueForKeyPath:“Content-Type”
set aHTML to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType

set aTextArray to ((aHTML’s nodesMatchingSelector:“a”)’s textContent) as list –リンク文字
set aLinkArray to ((aHTML’s nodesMatchingSelector:“a”)’s attributes’s valueForKeyPath:“href”) as list –URL
–> {”#start-of-content”, “https://github.com/”, “/personal”, “/open-source”, “/business”, “/explore”, “/join?source=header-repo”, “/login?return_to=%2Fnolanw%2FHTMLReader”, “/pricing”, “/blog”, …….}

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

AppleScript名:HTMLReaderでWeb上のHTMLから画像リンクを取得する
– Created 2016-11-21 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “HTMLReader” –https://github.com/nolanw/HTMLReader
–http://piyocast.com/as/archives/4325

set aStr to “https://github.com/nolanw/HTMLReader”
set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
if exRes = false then return –エラー発生時に処理打ち切り

set conType to headerRes’s valueForKeyPath:“Content-Type”
set aHTML to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType

set aLinkArray to ((aHTML’s nodesMatchingSelector:“img”)’s attributes’s valueForKeyPath:“src”) as list –画像リンクURLを取得
–> {”https://avatars2.githubusercontent.com/u/177228?v=3&s=40″, “https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif”, “https://assets-cdn.github.com/images/spinners/octocat-spinner-32.gif”, ….

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

2016/11/21 HTMLReaderでWeb上のHTMLを取得する

オープンソースのフレームワーク「HTMLReader」を用いて、指定のURLのHTMLをダウンロードして指定要素を取り出すAppleScriptです。

実行にあたっては、HTMLReaderをダウンロードしてビルドし、~/Library/Frameworksにインストールしておく必要があります。

Github上のページで紹介されているサンプルを翻訳したもので、そのうち「Load a web page.」をblocks構文を使わずに大幅に書き換えてみました。

AppleScript名:HTMLReaderのじっけん
– Created 2016-06-10 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
–http://piyocast.com/as/archives/4324

–Parse a string and find an element
set aMarkUp to current application’s NSString’s stringWithString:"<p><b>ぴよぴよ!</b><b>ぴよー</b></p>"
set aDocument to current application’s HTMLDocument’s documentWithString:aMarkUp
set anArray to ((aDocument’s nodesMatchingSelector:"b")’s textContent) as list
–>  {"ぴよぴよ!", "ぴよー"}

–Wrap one element in another.
set b to aDocument’s firstNodeMatchingSelector:"b"
set childArray to b’s parentNode()’s mutableChildren()
set aWrapper to current application’s HTMLElement’s alloc()’s initWithTagName:"div" attributes:{|class|:"special"}
childArray’s insertObject:aWrapper atIndex:(childArray’s indexOfObject:b)
b’s setParentNode:aWrapper
set htmlRes to (aDocument’s rootElement’s serializedFragment()) as string
–>  "<html><head></head><body><p><div class=\"special\"><b>ぴよぴよ!</b></div><b>ぴよー</b></p></body></html>"

★Click Here to Open This Script 

AppleScript名:HTMLReaderでWeb上のHTMLを取得する
– Created 2016-11-21 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader
–http://piyocast.com/as/archives/4324

set aStr to "https://github.com/nolanw/HTMLReader"
set aURL to (current application’s |NSURL|’s URLWithString:aStr)
set {exRes, headerRes, aData} to checkURLResourceExistence(aURL, 3) of me
if exRes = false then return –エラー発生時に処理打ち切り

–>  (NSDictionary) {Content-Encoding:"gzip", X-Runtime:"0.074184", Set-Cookie:"_gh_sess=eyJz…..",…….. X-Frame-Options:"deny", Content-Type:"text/html; charset=utf-8", X-Content-Type-Options:"nosniff", X-UA-Compatible:"IE=Edge,chrome=1"}

set conType to headerRes’s valueForKeyPath:"Content-Type"
–>  (NSString) "text/html; charset=utf-8"

set aHome to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType
set htmlSource to aHome’s rootElement()’s serializedFragment() –HTMLソース文字列

–(処理対象部分のみ掲載)
–> <meta content="HTMLReader - A WHATWG-compliant HTML parser in Objective-C." name="twitter:description">

set aDiv to aHome’s firstNodeMatchingSelector:".repository-meta-content"
set aWhiteSpace to current application’s NSCharacterSet’s whitespaceAndNewlineCharacterSet()
set dRes to (aDiv’s textContent()’s stringByTrimmingCharactersInSet:aWhiteSpace) as string
–>  "A WHATWG-compliant HTML parser in Objective-C."

– 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on checkURLResourceExistence(aURL, timeOutSec as real)
  set aRequest to (current application’s NSURLRequest’s requestWithURL:aURL cachePolicy:(current application’s NSURLRequestUseProtocolCachePolicy) timeoutInterval:timeOutSec)
  
set aRes to (current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value))
  
set dRes to (first item of (aRes as list))
  
set bRes to (second item of (aRes as list))
  
if bRes is not equal to missing value then
    set hRes to (bRes’s allHeaderFields())
    
set aResCode to (bRes’s statusCode()) as integer
  else
    set hRes to {}
    
set aResCode to -1 –error
  end if
  
return {(aResCode = 200), hRes, dRes}
end checkURLResourceExistence

★Click Here to Open This Script 

2016/11/17 ぐるなびの「レストラン検索API」でレストランを現在位置から3km以内でキーワード検索する

ぐるなびの「レストラン検索API」で、レストランを現在位置(CoreLocation経由で取得)から3km以内でキーワードを指定して検索するAppleScriptです。

実行のためには、ぐるなびAPIの「新規アカウント発行」より申請を行い、アクセスキーを取得してください(申請無料)。取得したアクセスキーをプログラム中のretAccessKey()ハンドラ中に記述しておいてください。また、現在位置取得のためにWiFiをオンにして実行する必要があります。初回実行時になかなか位置取得機能がイネーブルにならずに焦りました。

ぐるなびでは、「レストラン検索API」「多言語版レストラン検索API」「応援口コミAPI」「エリアマスタ取得API」「都道府県マスタAPI」「エリアLマスタAPI」「エリアMマスタAPI」「エリアSマスタAPI」「大業態マスタ取得API」「小業態マスタ取得API」などのAPIを公開しているため、さまざまなアプリケーション上のデータと組み合わせて有効に利用できると思います。

下世話なところでは、Webサイトから検索すると無駄なデータが多い割に一度に検索できるデータ件数が少ないので、(Webブラウザではなく)スクリプトエディタ上でしぼりこみ検索を行っていたりします。

プログラムの難易度は高くないのですが、ふだんライブラリ化している部品を掲載のために1リスト中に展開しています。内容が素朴な割にプログラムが長くなってしまっていますが、AppleScriptObjCの宿命といったところでしょうか。

AppleScript名:ぐるなびの「レストラン検索API」でレストランを現在位置から3km以内でキーワード検索する
– Created 2016-10-29 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
use framework “CoreLocation”
–use curLocLib : script “curLocationLib”
–http://api.gnavi.co.jp/api/manual/restsearch/

–http://piyocast.com/as/archives/4320

–from curLocationLib
property locationManager : missing value
property curLatitude : 0
property curLongitude : 0
–from curLocationLib

set reqURLStr to “http://api.gnavi.co.jp/RestSearchAPI/20150630/”

–現在地の緯度、経度情報を取得する
set {aLat, aLong} to getCurrentLocation() of me
set aKey to retAccessKey() of me

–指定位置から3km以内の、キーワード”とんかつ”でヒットするレストランをピックアップ
set aRec to {keyid:aKey, |format|:“json”, latitude:aLat as string, longitude:aLong as string, range:“5″, freeword:“とんかつ”}
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseResults(aURL) of me
set aRESCode to responseCode of aRes
if aRESCode is not equal to 200 then return false
set aRESHeader to responseHeader of aRes
set aRESTres to (json of aRes)
–>  {@attributes:{api_version:”20150630″}, total_hit_count:”24″, page_offset:”1″, rest:{{name_kana:”アサノ”, address:”〒179-0074 東京都練馬区春日町6-12-5 “, party:{}, credit_card:{}, url:”http://r.gnavi.co.jp/nhefra550000/?ak=Q%2BN8L78dCT2RgZUYqtECBTRS3%2BEtZ0qY0cmsoQMxWqU%3D”, code:{category_name_l:{”和食”, {@attributes:{order:”1″}}}, areaname:”関東”, areacode:”AREA110″, prefname:”東京都”, prefcode:”PREF13″, areacode_s:”AREAS2225″, areaname_s:”光が丘”, category_code_s:{”RSFST01005″, {@attributes:{order:”1″}}}, category_code_l:{”RSFST01000″, {@attributes:{order:”1″}}}, category_name_s:{”とんかつ(トンカツ)”, {@attributes:{order:”1″}}}}, tel:”03-3999-4099″, parking_lots:{}, lunch:{}, fax:{}, @attributes:{order:”0″}, latitude:”35.747856″, category:”とんかつ”, url_mobile:”http://mobile.gnavi.co.jp/shop/5421186/?ak=Q%2BN8L78dCT2RgZUYqtECBTRS3%2BEtZ0qY0cmsoQMxWqU%3D”, name:”あさの “, holiday:{}, flags:{mobile_site:”1″, mobile_coupon:”0″, pc_coupon:”0″}, id:”5421186″, coupon_url:{mobile:{}, pc:{}}, access:{walk:”徒歩7″, line:”都営大江戸線(放射部)”, station_exit:”A3口”, note:{}, station:”練馬春日町駅”}, tel_sub:{}, longitude:”139.637081″, pr:{pr_long:{}, pr_short:{}}, budget:{}, e_money:{}, opentime:{}, update_date:”2015-10-14 14:14:02″, image_url:{shop_image1:{}, shop_image2:{}, qrcode:”http://r.gnst.jp/tool/qr/?id=5421186&q=6″}}, ….

set aNameRes to (aRESTres’s valueForKeyPath:“rest.name”) as list
–>  {”あさの “, “CoCo壱番屋 西武中村橋駅前通店”, “とんかつ かつ富士 “, “華屋与兵衛 豊島園店”, “華屋与兵衛 春日町店”, “とんかつ和幸 西武練馬駅店 “, “とんかつ和幸 IMA光が丘店 “, “松乃家 練馬店”, “とん陣 “, “よしだ “}

set aAddressRes to (aRESTres’s valueForKeyPath:“rest.address”) as list
–>  {”〒179-0074 東京都練馬区春日町6-12-5 “, “〒176-0023 東京都練馬区中村北3-22-10 友伸ビル1F”, “〒176-0021 東京都練馬区貫井3-14-5 “, “〒179-0085 東京都練馬区早宮4-39″, “〒179-0074 東京都練馬区春日町2-7-18″, “〒176-0001 東京都練馬区練馬1-3-5 西武池袋線練馬駅下 2F”, “〒179-0072 東京都練馬区光が丘5-1-1 光が丘IMA内 3F”, “〒176-0012 東京都練馬区豊玉北5-19-12″, “〒176-0012 東京都練馬区豊玉北5-18-7 “, “〒179-0073 東京都練馬区田柄1-4-24 “}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

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 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

on retAccessKey()
  return “xxXxXXxxXxxxXxxXXxXXxXXxXxXXxxXX” –ぐるなびAPI アカウントのアクセスキー
end retAccessKey

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

——————————————————–
— curLocationLib

on getCurrentLocation()
  
  
set locationManager to current application’s CLLocationManager’s alloc()’s init()
  
  
set locE to locationManager’s locationServicesEnabled()
  
if (locE as boolean) = true then
    locationManager’s setDelegate:me
    
locationManager’s setDesiredAccuracy:(current application’s kCLLocationAccuracyNearestTenMeters)
    
locationManager’s setDistanceFilter:500
    
locationManager’s startUpdatingLocation()
  else
    return false –error in init
  end if
  
  
set hitF to false
  
repeat 3000 times
    if {curLatitude, curLongitude} is not equal to {0, 0} then
      set hitF to true
      
exit repeat
    end if
    
delay 0.01
  end repeat
  
  
if hitF = false then return false
  
return {curLatitude, curLongitude}
  
end getCurrentLocation

on locationManager:manager didUpdateLocations:locations
  –Listing 1-3 Processing an incoming location event
  
set location to (locations’s lastObject())
  
set eventDate to (location’s timestamp())
  
set howRecent to (eventDate’s timeIntervalSinceNow())
  
  
–Calc ABS
  
set howRecent to howRecent as real
  
set howRecent to absNum(howRecent)
  
  
if howRecent < 15.0 then
    set alt to location’s altitude
    
set aSpeed to location’s speed
    
set aCourse to location’s course –North:0, East:90, South:180, West:270
    
set theDescription to location’s |description|()
    
set anNSScanner to current application’s NSScanner’s scannerWithString:theDescription
    
anNSScanner’s setCharactersToBeSkipped:(current application’s NSCharacterSet’s characterSetWithCharactersInString:“< ,")
    
set {theResult, aLat} to anNSScanner’s scanDouble:(reference)
    
set {theResult, aLng} to anNSScanner’s scanDouble:(reference)
    
    
copy {aLat, aLng} to {my curLatitude, my curLongitude}
  else
    locationManager’s stopUpdatingLocation()
  end if
end locationManager:didUpdateLocations:

on locationManager:anCLLocationManager didFailWithError:anNSError
  display dialog (anNSError’s localizedDescription() as text)
end locationManager:didFailWithError:

on absNum(aNum)
  if aNum > 0 then
    return aNum
  else
    return (aNum * -1)
  end if
end absNum

★Click Here to Open This Script 

2016/11/05 XMLをNSDictionaryに

オープンソースのXMLDictionary(By Nick Lockwood)をFramework化した「XmlToDictKit」を呼び出して、XMLをNSDictionaryにするAppleScriptです。

XMLをNSDictionaryにするのには、なかなか手こずらされており、依然としてSatimageのXMLLib OSAXが手放せない状況ですが、OSAXを使わずになんとかする方法についてはつねに模索しておりました。

「XML Parser」などをキーワードにGithub上でいろいろ物色していたところ、そんなに気合の入ったキーワードでなくても、「XML NSDictionary」ぐらいでいろいろ見つかりました。

それらを人気順でソートし上から順番に物色。条件が合って手軽にフレームワーク化に成功したのがこの「XMLDictionary」です。

XMLをNSDictionaryに変換し、さらにNSDictionaryをrecordまで変換すればAppleScriptで簡単に取り扱えます(NSDictionaryの属性値ラベルに空白などが入っていなければ)。

フレームワークについては、例によってOS X 10.10をターゲットにしてビルドしてみました。~/Library/Frameworksに入れてご利用ください(あくまで自己責任で)。

XMLそのものよりも、RSSのParseが割と手間だったので、RSSを手軽に扱えるようになったことのメリットが大きいと感じています。

→ FrameworkのZipアーカイブのダウンロード(30KB)

AppleScript名:XMLをDictionaryに(remote file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aURL to current application’s |NSURL|’s alloc()’s initWithString:“http://www.ibiblio.org/xml/examples/shakespeare/all_well.xml”
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record

★Click Here to Open This Script 

AppleScript名:XMLをDictionaryに(local file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aFile to POSIX path of (choose file)
set aURL to current application’s |NSURL|’s fileURLWithPath:aFile
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record

★Click Here to Open This Script 

AppleScript名:RSSをDictionaryに(remote file)
– Created 2016-11-05 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “XmlToDictKit” –https://github.com/nicklockwood/XMLDictionary
–http://piyocast.com/as/archives/4304

set aURL to current application’s |NSURL|’s alloc()’s initWithString:“http://piyocast.com/as/feed”
set xmlString to current application’s NSString’s alloc()’s initWithContentsOfURL:aURL encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
if xmlString = missing value then return false
set xmlDoc to (current application’s NSDictionary’s dictionaryWithXMLString:xmlString) as record
set aChannel to |item| of channel of xmlDoc
set aDoc1 to first item of aChannel
–>  {category:{”Application Control”, “10.10 savvy”, “10.11 savvy”, “10.12 savvy”}, dc:creator:”maro”, comments:”http://piyocast.com/as/archives/4304#comments”, title:”XMLをNSDictionaryに”, link:”http://piyocast.com/as/archives/4304″, pubDate:”Sat, 05 Nov 2016 21:21:17 +0900″, description:”オープンソースのXMLDictionary(By Nick Lockwood)をFramework化した「XmlToDictKit」を呼び出して、XMLをNSDictionaryにするAppleScr…”, guid:{__text:”http://piyocast.com/as/archives/4304″, _isPermaLink:”false”}, wfw:commentRss:”http://piyocast.com/as/archives/4304/feed/”}

★Click Here to Open This Script 

2016/11/02 connpassイベントサーチAPIで検索を行う

connpassイベントサーチAPIで検索を行うAppleScriptです。

エンジニアをつなぐIT勉強会支援プラットフォームであるconnpassのサイトでは、イベントサーチAPIを用意しており、

  event_id(イベントID)
  keyword(キーワード (AND))
  keyword_or(キーワード (OR))
  ym(イベント開催年月)
  ymd(イベント開催年月日)
  nickname(参加者のニックネーム)
  owner_nickname(管理者のニックネーム)
  series_id(グループID)

などの検索キーをもとにイベントを検索できます。あー、自分の登録したイベントが見つかってよかったー、という確認です。

# 先日、connpassイベントサーチAPIがhttps経由でのアクセスに変更されたため、本リストも修正しておきました

AppleScript名:connpassイベントサーチAPIで検索を行うv2
– Created 2016-10-29 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
–http://connpass.com/about/api/
–http://piyocast.com/as/archives/4300

set reqURLStr to "https://connpass.com/api/v1/event/"

set aRec to {keyword:"AppleScript", ym:"201611"} –サーチクエリーと対象月
set aURL to retURLwithParams(reqURLStr, aRec) of me
set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>
(*
{results_available:1, results_start:1, |events|:{{place:"マイ・スペース MS&BB 池袋西武横店 1号室", event_url:"http://ashole.connpass.com/event/44103/", accepted:2, title:"AppleScript本フィードバック会", limit:7, event_type:"participation", owner_id:64136, ended_at:"2016-11-26T20:30:00+09:00", updated_at:"2016-11-01T09:22:15+09:00", lon:"139.711383200000", waiting:0, event_id:44103, hash_tag:"AppleScript,Mac,macOS,Mac OS X", owner_nickname:"Piyomaru", lat:"35.726486900000", started_at:"2016-11-26T18:30:00+09:00", owner_display_name:"Piyomaru", catch:"「AppleScript最新リファレンス」「AppleScript最新10大技術」についての解説", series:{|url|:"http://ashole.connpass.com/", |id|:3041, title:"AppleScriptの穴"}, address:"〒171-0022 東京都豊島区南池袋1-16-20(ぬかりやビル2階)", |description|:"<p>macOS標準装備で、GUIアプリケーションを操作できるマクロ言語「AppleScript」、その20年以上の歴史をまとめ、最新情報を盛り込んだ電子書籍「AppleScript最新リファレンス」「AppleScript 最新10大技術」を発行いたしました。</p>\n<p>・電子書籍オンライン販売URL\n<a href=\"https://piyomarusoft.booth.pm\" rel=\"nofollow\">https://piyomarusoft.booth.pm</a></p>\n<p>これらの本について、分からない点やもっと知りたい点について、筆者本人と直接お話できる場を設けました。</p>\n<p>参加資格は、AppleScriptを実際に使っている方、興味を持っている方で、筆者の書籍を実際に購入した、あるいは購入しようと考えている方です。事前に内容を読んであることが望ましいです。</p>\n<p>筆者Blog「AppleScriptの穴」\n<a href=\"http://piyocast.com/as/\" rel=\"nofollow\">http://piyocast.com/as/</a></p>"}}, results_returned:1}
*)

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
end callRestGETAPIAndParseResults

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 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

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

★Click Here to Open This Script 

2016/11/01 日本語形態素解析【新語対応】

Apitoreの「日本語形態素解析【新語対応】」REST APIを呼び出して、指定の日本語の形態素解析を行うAppleScriptです。使用している形態素解析エンジンはJavaベースの「Kuromoji」とのこと。

IPADICを辞書に使うバージョンと、IPADIC NEologdを辞書に使うバージョンの2つのAPIがあり、それぞれ同じ文章で形態素解析を行っています。NEologdのほうは「きゃりーぱみゅぱみゅ」などの新しめの固有名詞が登録されており、単語として認識します。

その一方で、やはり人名などの固有名詞(例:自分のなまえ)が正しく単語として認識されないと困るので、形態素解析についてはローカルの日本語入力IMやアドレスブックに登録してある人名との連携は欠かせないと思うものであります(IMの学習は「間違っている」ケースもあるので難しいところですが)。

実行前にapitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

AppleScript名:日本語形態素解析【新語対応】_ipadic
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4299

set reqURLStr to “https://api.apitore.com/api/7/kuromoji-ipadic/tokenize”
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |text|:“私の名前はきゃりーぱみゅぱみゅです。”}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {startTime:”1477627346754″, tokens:{{partOfSpeechLevel1:”名詞”, baseForm:”私”, pronunciation:”ワタシ”, position:0, partOfSpeechLevel3:”一般”, reading:”ワタシ”, surface:”私”, known:true, allFeatures:”名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ”, conjugationType:”*”, partOfSpeechLevel2:”代名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “代名詞”, “一般”, “*”, “*”, “*”, “私”, “ワタシ”, “ワタシ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”の”, pronunciation:”ノ”, position:1, partOfSpeechLevel3:”*”, reading:”ノ”, surface:”の”, known:true, allFeatures:”助詞,連体化,*,*,*,*,の,ノ,ノ”, conjugationType:”*”, partOfSpeechLevel2:”連体化”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “連体化”, “*”, “*”, “*”, “*”, “の”, “ノ”, “ノ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”名前”, pronunciation:”ナマエ”, position:2, partOfSpeechLevel3:”*”, reading:”ナマエ”, surface:”名前”, known:true, allFeatures:”名詞,一般,*,*,*,*,名前,ナマエ,ナマエ”, conjugationType:”*”, partOfSpeechLevel2:”一般”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “一般”, “*”, “*”, “*”, “*”, “名前”, “ナマエ”, “ナマエ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”動詞”, baseForm:”はく”, pronunciation:”ハキャ”, position:4, partOfSpeechLevel3:”*”, reading:”ハキャ”, surface:”はきゃ”, known:true, allFeatures:”動詞,自立,*,*,五段・カ行イ音便,仮定縮約1,はく,ハキャ,ハキャ”, conjugationType:”五段・カ行イ音便”, partOfSpeechLevel2:”自立”, conjugationForm:”仮定縮約1”, allFeaturesArray:{”動詞”, “自立”, “*”, “*”, “五段・カ行イ音便”, “仮定縮約1”, “はく”, “ハキャ”, “ハキャ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助動詞”, baseForm:”り”, pronunciation:”リ”, position:7, partOfSpeechLevel3:”*”, reading:”リ”, surface:”り”, known:true, allFeatures:”助動詞,*,*,*,文語・リ,基本形,り,リ,リ”, conjugationType:”文語・リ”, partOfSpeechLevel2:”*”, conjugationForm:”基本形”, allFeaturesArray:{”助動詞”, “*”, “*”, “*”, “文語・リ”, “基本形”, “り”, “リ”, “リ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”*”, pronunciation:”*”, position:8, partOfSpeechLevel3:”一般”, reading:”*”, surface:”ー”, known:false, allFeatures:”名詞,固有名詞,一般,*,*,*,*,*,*”, conjugationType:”*”, partOfSpeechLevel2:”固有名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “固有名詞”, “一般”, “*”, “*”, “*”, “*”, “*”, “*”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”*”, pronunciation:”*”, position:9, partOfSpeechLevel3:”*”, reading:”*”, surface:”ぱみゅぱみゅです”, known:false, allFeatures:”名詞,一般,*,*,*,*,*,*,*”, conjugationType:”*”, partOfSpeechLevel2:”一般”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “一般”, “*”, “*”, “*”, “*”, “*”, “*”, “*”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”記号”, baseForm:”。”, pronunciation:”。”, position:17, partOfSpeechLevel3:”*”, reading:”。”, surface:”。”, known:true, allFeatures:”記号,句点,*,*,*,*,。,。,。”, conjugationType:”*”, partOfSpeechLevel2:”句点”, conjugationForm:”*”, allFeaturesArray:{”記号”, “句点”, “*”, “*”, “*”, “*”, “。”, “。”, “。”}, partOfSpeechLevel4:”*”}}, endTime:”1477627346755″, log:”", processTime:”1″}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json;charset=UTF-8″, Access-Control-Allow-Origin:”*”, Pragma:”no-cache”, X-XSS-Protection:”1; mode=block, 1; mode=block”, Server:”nginx/1.10.1″, Transfer-Encoding:”Identity”, Expires:”0″, Cache-Control:”no-cache, no-store, max-age=0, must-revalidate”, Date:”Thu, 27 Oct 2016 03:19:17 GMT”, Strict-Transport-Security:”max-age=31536000; includeSubDomains;”, Connection:”keep-alive”, X-Content-Type-Options:”nosniff, nosniff”, X-Frame-Options:”DENY, SAMEORIGIN”}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

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 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

on retAccessToken()
  return “XXxXXXxx-XXxX-XXXx-XXxX-XXxxXxXXXxXX” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

AppleScript名:日本語形態素解析【新語対応】_ipadic_neologd
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4299

set reqURLStr to “https://api.apitore.com/api/7/kuromoji-ipadic-neologd/tokenize”
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |text|:“私の名前はきゃりーぱみゅぱみゅです。”}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {startTime:”1477998343747″, tokens:{{partOfSpeechLevel1:”名詞”, baseForm:”私”, pronunciation:”ワタシ”, position:0, partOfSpeechLevel3:”一般”, reading:”ワタシ”, surface:”私”, known:true, allFeatures:”名詞,代名詞,一般,*,*,*,私,ワタシ,ワタシ”, conjugationType:”*”, partOfSpeechLevel2:”代名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “代名詞”, “一般”, “*”, “*”, “*”, “私”, “ワタシ”, “ワタシ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”の”, pronunciation:”ノ”, position:1, partOfSpeechLevel3:”*”, reading:”ノ”, surface:”の”, known:true, allFeatures:”助詞,連体化,*,*,*,*,の,ノ,ノ”, conjugationType:”*”, partOfSpeechLevel2:”連体化”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “連体化”, “*”, “*”, “*”, “*”, “の”, “ノ”, “ノ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”名前”, pronunciation:”ナマエ”, position:2, partOfSpeechLevel3:”*”, reading:”ナマエ”, surface:”名前”, known:true, allFeatures:”名詞,一般,*,*,*,*,名前,ナマエ,ナマエ”, conjugationType:”*”, partOfSpeechLevel2:”一般”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “一般”, “*”, “*”, “*”, “*”, “名前”, “ナマエ”, “ナマエ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助詞”, baseForm:”は”, pronunciation:”ワ”, position:4, partOfSpeechLevel3:”*”, reading:”ハ”, surface:”は”, known:true, allFeatures:”助詞,係助詞,*,*,*,*,は,ハ,ワ”, conjugationType:”*”, partOfSpeechLevel2:”係助詞”, conjugationForm:”*”, allFeaturesArray:{”助詞”, “係助詞”, “*”, “*”, “*”, “*”, “は”, “ハ”, “ワ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”名詞”, baseForm:”きゃりーぱみゅぱみゅ”, pronunciation:”キャリーパミュパミュ”, position:5, partOfSpeechLevel3:”一般”, reading:”キャリーパミュパミュ”, surface:”きゃりーぱみゅぱみゅ”, known:true, allFeatures:”名詞,固有名詞,一般,*,*,*,きゃりーぱみゅぱみゅ,キャリーパミュパミュ,キャリーパミュパミュ”, conjugationType:”*”, partOfSpeechLevel2:”固有名詞”, conjugationForm:”*”, allFeaturesArray:{”名詞”, “固有名詞”, “一般”, “*”, “*”, “*”, “きゃりーぱみゅぱみゅ”, “キャリーパミュパミュ”, “キャリーパミュパミュ”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”助動詞”, baseForm:”です”, pronunciation:”デス”, position:15, partOfSpeechLevel3:”*”, reading:”デス”, surface:”です”, known:true, allFeatures:”助動詞,*,*,*,特殊・デス,基本形,です,デス,デス”, conjugationType:”特殊・デス”, partOfSpeechLevel2:”*”, conjugationForm:”基本形”, allFeaturesArray:{”助動詞”, “*”, “*”, “*”, “特殊・デス”, “基本形”, “です”, “デス”, “デス”}, partOfSpeechLevel4:”*”}, {partOfSpeechLevel1:”記号”, baseForm:”。”, pronunciation:”。”, position:17, partOfSpeechLevel3:”*”, reading:”。”, surface:”。”, known:true, allFeatures:”記号,句点,*,*,*,*,。,。,。”, conjugationType:”*”, partOfSpeechLevel2:”句点”, conjugationForm:”*”, allFeaturesArray:{”記号”, “句点”, “*”, “*”, “*”, “*”, “。”, “。”, “。”}, partOfSpeechLevel4:”*”}}, endTime:”1477998343748″, |log|:”", processTime:”1″}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes
–>  {Content-Type:”application/json;charset=UTF-8″, Access-Control-Allow-Origin:”*”, Pragma:”no-cache”, X-XSS-Protection:”1; mode=block, 1; mode=block”, Server:”nginx/1.10.1″, Transfer-Encoding:”Identity”, Expires:”0″, Cache-Control:”no-cache, no-store, max-age=0, must-revalidate”, Date:”Thu, 27 Oct 2016 03:19:17 GMT”, Strict-Transport-Security:”max-age=31536000; includeSubDomains;”, Connection:”keep-alive”, X-Content-Type-Options:”nosniff, nosniff”, X-Frame-Options:”DENY, SAMEORIGIN”}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

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 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

on retAccessToken()
  return “XXxXXXxx-XXxX-XXXx-XXxX-XXxxXxXXXxXX” –API Tore Access Token
end retAccessToken

★Click Here to Open This Script 

2016/10/29 同義語辞書【新語対応】

Apitoreの「同義語辞書【新語対応】」APIを呼び出して、指定の日本語の単語の同義語(っぽいもの)を返すAppleScriptです。

実行前にapitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

一般的なシソーラス的な動作を行うわけではなく、固有名詞に特化しているとのこと。そこで、「ガンダム」を渡してみたところ、

{input:”ガンダム”, endTime:”1477742279389″, processTime:”1019″, log:”Success.”, distances:{{word:”ζガンダム”, distance:0.819100677967}, {word:”rx-78″, distance:0.798426866531}, {word:”ζζガンダム”, distance:0.794555306435}, {word:”ザク”, distance:0.783695220947}, {word:”zガンダム”, distance:0.776543617249}, {word:”フルアーマー”, distance:0.757733106613}, {word:”gアーマー”, distance:0.75621265173}, {word:”νガンダム”, distance:0.754522383213}, {word:”ガンキャノン”, distance:0.752012193203}, {word:”モビルスーツ”, distance:0.744036734104}}, startTime:”1477742278370″, num:”10″}

やや、ゴミ(ζガンダム、ζζガンダム)が入っているようです。また、「グフ・カスタム」を入力してみると、

{input:”グフ・カスタム”, endTime:”1477742501687″, processTime:”934″, log:”Success.”, distances:{{word:”sideral”, distance:0.922877013683}, {word:”北海道道104号網走端野線”, distance:0.922159075737}, {word:”北海道道966号十勝岳温泉美瑛線”, distance:0.921318411827}, {word:”kuttner”, distance:0.916471898556}, {word:”北海道道102号網走川湯線”, distance:0.915675938129}, {word:”北海道道42号八雲北檜山線”, distance:0.915441274643}, {word:”三浦隆”, distance:0.914838135242}, {word:”桧山泰浩”, distance:0.914380848408}, {word:”北海道道120号美深中頓別線”, distance:0.914329528809}, {word:”knipex”, distance:0.913379848003}}, startTime:”1477742500753″, num:”10″}

と、関係ない言葉が返ってくるようです。Wikipediaに項目が単独で存在しているような単語と、その関連語では本サービス上での扱いが異なるように感じられます。

AppleScript名:同義語辞書【新語対応】
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.5″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4294

set reqURLStr to “https://api.apitore.com/api/9/word2vec-neologd-jawiki/distance”
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |word|:“ガンダム”, num:“10″}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {input:”ガンダム”, endTime:”1477742279389″, processTime:”1019″, log:”Success.”, distances:{{word:”ζガンダム”, distance:0.819100677967}, {word:”rx-78″, distance:0.798426866531}, {word:”ζζガンダム”, distance:0.794555306435}, {word:”ザク”, distance:0.783695220947}, {word:”zガンダム”, distance:0.776543617249}, {word:”フルアーマー”, distance:0.757733106613}, {word:”gアーマー”, distance:0.75621265173}, {word:”νガンダム”, distance:0.754522383213}, {word:”ガンキャノン”, distance:0.752012193203}, {word:”モビルスーツ”, distance:0.744036734104}}, startTime:”1477742278370″, num:”10″}

–>  {input:”グフ・カスタム”, endTime:”1477742501687″, processTime:”934″, log:”Success.”, distances:{{word:”sideral”, distance:0.922877013683}, {word:”北海道道104号網走端野線”, distance:0.922159075737}, {word:”北海道道966号十勝岳温泉美瑛線”, distance:0.921318411827}, {word:”kuttner”, distance:0.916471898556}, {word:”北海道道102号網走川湯線”, distance:0.915675938129}, {word:”北海道道42号八雲北檜山線”, distance:0.915441274643}, {word:”三浦隆”, distance:0.914838135242}, {word:”桧山泰浩”, distance:0.914380848408}, {word:”北海道道120号美深中頓別線”, distance:0.914329528809}, {word:”knipex”, distance:0.913379848003}}, startTime:”1477742500753″, num:”10″}

set aRESCode to responseCode of aRes
–>  200

set aRESHeader to responseHeader of aRes

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:“GET”
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:“application/json” forHTTPHeaderField:“Accept”
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

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

on retAccessToken()
  return “XXxXXXxx-XXxX-XXXx-XXxX-XXxxXxXXXxXX” –API Tore Access Token
end retAccessToken

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

★Click Here to Open This Script 

2016/10/27 感情推定【極性判定】

Apitore「感情推定」APIを呼び出して、指定の日本語の文章がPositive(肯定的)かNegative(否定的)かを判定するAppleScriptです。

実行前にapitoreにユーザー登録を行い(無料)、Web上でアクセストークンを取得。そのトークンをretAccessToken()内で返すように書いておく必要があります(掲載のリストのまま実行すると、エラーになります。かならずアクセストークンを取得してください)。

用途は割といろいろあって、ちょっと考えただけでも、

「メールの文面をチェックして、日本語であれば(NSLinguisticTaggerを使って判定)感情推定APIを呼び出し、Negativeと判定されたらメールの一覧に赤く色をつける」

とかいうAppleScriptはかんたんに書けますし、便利だと思います(色付きメールを読みたくなくなる、とかいう心理的なフィードバックが発生することについてはさておき)。

また、

Safariの閲覧履歴を取得して、各URLにアクセスして本文のみ取得。読んだ内容がPositveかNegativeかの内訳をグラフで表示」

とかいうのも面白そうです。

テストしてみたところ、たまたまサーバー側で問題を起こしていた最中のようで、サンプルプログラム中に記述してある「かならずPositive(肯定的)と判定される例文」がNegative(否定的)と出てきて焦りましたが、じきに安定することでしょう。

AppleScript名:感情推定【極性判定】
– Created 2016-10-27 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
–http://piyocast.com/as/archives/4289

set aText to "おめでとう!カブスが4勝2敗でドジャースを下し、2016年ナ・リーグの覇者に!次は水曜日(10月26日)に行われるワールドシリーズでア・リーグの覇者インディアンスと対決!"

set reqURLStr to "https://api.apitore.com/api/11/sentiment/predict"
set accessToken to retAccessToken() —Access Token
set aRec to {access_token:accessToken, |text|:aText}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL) of me

set aRESTres to (json of aRes) as record
return aRESTres
–>  {endTime:"1477617363491", processTime:"44", text:"おめでとう!カブスが4勝2敗でドジャースを下し、2016年ナ・リーグの覇者に!次は水曜日(10月26日)に行われるワールドシリーズでア・リーグの覇者インディアンスと対決!", log:"Success.", predict:{score:0.520746946335, sentiment:"positive"}, startTime:"1477617363447", sentimens:{{score:0.520746946335, sentiment:"positive"}, {score:0.479253053665, sentiment:"negative"}}}

–set aRESCode to (responseCode of aRes) as integer
–>  200

–set aRESHeader to (responseHeader of aRes) as record
–>  {Content-Type:"application/json;charset=UTF-8", Access-Control-Allow-Origin:"*", Pragma:"no-cache", X-XSS-Protection:"1; mode=block, 1; mode=block", Server:"nginx/1.10.1", Transfer-Encoding:"Identity", Expires:"0", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Date:"Thu, 27 Oct 2016 03:22:11 GMT", Strict-Transport-Security:"max-age=31536000; includeSubDomains;", Connection:"keep-alive", X-Content-Type-Options:"nosniff, nosniff", X-Frame-Options:"DENY, SAMEORIGIN"}

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL)
  
  
set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:60
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code & Header
  
set dRes to contents of second item of resList
  
if dRes is not equal to missing value then
    set resCode to (dRes’s statusCode()) as number
    
set resHeaders to (dRes’s allHeaderFields()) as record
  else
    set resCode to 0
    
set resHeaders to {}
  end if
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retAccessToken()
  return "xxxXxxXx-XXXX-XXXX-XxXX-XXxXXxxXXxxx" –API Tore Access Token
end retAccessToken

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 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/10/25 指定ムービーを指定形式に変換する v2

指定のムービーファイルを指定形式に変換するAppleScriptの改良版です。

一晩たったら、旧石器時代から現代までタイムスリップしたぐらいの改良が加わっています(汗)。野蛮な手段でファイル拡張子からUTIを求めていたのが、フレームワーク呼び出し一発で、、、処理速度も大幅に向上しています。

AppleScript名:指定ムービーを指定形式に変換する v2
– Created 2016-10-24 by Shane Stanley
– Modified 2016-10-24 by Takaaki Naganoya
– Modified 2016-10-25 by Shane Stanley
use AppleScript version “2.4″
use framework “Foundation”
use framework “AVFoundation”
use scripting additions
use BridgePlus : script “BridgePlus” –Version 1.3.2以降

load framework
–http://piyocast.com/as/archives/4288

set posixPath to POSIX path of (choose file with prompt “Choose a Movie file:”)
my convertMovieAt:posixPath ToType:“AVAssetExportPresetAppleM4A” withExtension:“m4a” deleteOriginal:false

–指定のムービーを、指定の書き出しプリセットで、指定のファイル形式で、オリジナルファイルを削除するかどうか指定しつつ書き出し
on convertMovieAt:(posixPath as string) ToType:(assetTypeStr as string) withExtension:(aExt as string) deleteOriginal:(deleteFlag as boolean)
  set theURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
  
set aPreset to current application’s NSString’s stringWithString:assetTypeStr
  
  
– set destination to use same path, different extension
  
set destURL to theURL’s URLByDeletingPathExtension()’s URLByAppendingPathExtension:aExt
  
set theAsset to current application’s AVAsset’s assetWithURL:theURL
  
  
– check asset can be converted
  
set allowedPresets to current application’s AVAssetExportSession’s exportPresetsCompatibleWithAsset:theAsset
  
if (allowedPresets’s containsObject:aPreset) as boolean is false then
    error “Can’t export this file as an .” & aExt & ” file.”
  end if
  
  
– set up export session
  
set fileTypeUTIstr to retFileFormatUTI(aExt) of me –ファイル拡張子からFile Type UTIを求める
  
set theSession to current application’s AVAssetExportSession’s exportSessionWithAsset:theAsset presetName:aPreset
  
theSession’s setOutputFileType:fileTypeUTIstr
  
theSession’s setOutputURL:destURL
  
  
– begin export and poll for completion
  
theSession’s exportAsynchronouslyWithCompletionHandler:(missing value)
  
repeat
    set theStatus to theSession’s status() as integer
    
if theStatus < 3 then
      delay 0.2
    else
      exit repeat
    end if
  end repeat
  
  
– throw error if it failed
  
if theStatus = (current application’s AVAssetExportSessionStatusFailed) as integer then
    error (theSession’s |error|()’s localizedDescription() as text)
  end if
  
  
– delete original if required
  
if deleteFlag then
    current application’s NSFileManager’s defaultManager()’s removeItemAtURL:theURL |error|:(missing value)
  end if
end convertMovieAt:ToType:withExtension:deleteOriginal:

on retFileFormatUTI(aExt as string)
  return (current application’s SMSForder’s UTIForExtension:aExt)
end retFileFormatUTI

★Click Here to Open This Script 

2016/10/25 ムービー系の拡張子からFile Format UTIを取得する v2, v3

ムービー系のファイルの拡張子から、File Format UTIを取得するAppleScriptの改良版です。

Shane Stanleyから指摘があって、

(1)com.apple.quicktime-movieと current application’s AVFileTypeQuickTimeMovieは同じものなので変換する必要はないよ(なんとなく、そうじゃないかとは思ってました ^ー^;;)

(2)BridgePlus v1.3.2に拡張子からUTIを求めるメソッドが用意してあるよ(!!!)

というわけで、(1)を反映させたv2、(2)まで反映させたv3を作成してみましたが、v3にいたってはたったの1行。どこかにもっとスマートな解決策が転がっていると思っていましたが、ここまでスマートになるとは(^ー^;;;

一応、試した範囲ではv1もv2もv3も実行結果は同じです。

AppleScript名:ムービー系の拡張子からFile Format UTIを取得する v2
– Created 2016-10-24 by Takaaki Naganoya
– Modified 2016-10-25 by Takaaki Naganoya
– Modified 2016-10-25 by Shane Stanley
– 2016 Piyomaru Software
use AppleScript version “2.4″
use framework “Foundation”
use framework “AVFoundation”
use framework “AppKit”
use scripting additions
–http://piyocast.com/as/archives/4287

set aRes to retFileFormatUTI(“mov”) of me
–>  (NSString) “com.apple.quicktime-movie”

set aRes to retFileFormatUTI(“mp4″) of me
–>  (NSString) “public.mpeg-4″

set aRes to retFileFormatUTI(“m4v”) of me
–>  (NSString) “com.apple.m4v-video”

set aRes to retFileFormatUTI(“m4a”) of me
–>  (NSString) “com.apple.m4a-audio”

set aRes to retFileFormatUTI(“3gp”) of me
–>  (NSString) “public.3gpp”

set aRes to retFileFormatUTI(“3gp2″) of me
–>  (NSString) “public.3gpp2″

set aRes to retFileFormatUTI(“caf”) of me
–>  (NSString) “com.apple.coreaudio-format”

set aRes to retFileFormatUTI(“wav”) of me
–>  (NSString) “com.microsoft.waveform-audio”

set aRes to retFileFormatUTI(“aif”) of me
–>  (NSString) “public.aifc-audio”

set aRes to retFileFormatUTI(“aifc”) of me
–>  (NSString) “public.aifc-audio”

set aRes to retFileFormatUTI(“amr”) of me
–>  (NSString) “org.3gpp.adaptive-multi-rate-audio”

set aRes to retFileFormatUTI(“mp3″) of me
–>  (NSString) “public.mp3″

set aRes to retFileFormatUTI(“au”) of me
–>  (NSString) “public.au-audio”

set aRes to retFileFormatUTI(“ac3″) of me
–>  (NSString) “public.ac3-audio”

on retFileFormatUTI(aExt)
  set theWorkspace to current application’s NSWorkspace’s sharedWorkspace()
  
set valList to {“com.apple.quicktime-movie”, “public.mpeg-4″, “com.apple.m4v-video”, “com.apple.m4a-audio”, “public.3gpp”, “public.3gpp2″, “com.apple.coreaudio-format”, “com.microsoft.waveform-audio”, “public.aiff-audio”, “public.aifc-audio”, “org.3gpp.adaptive-multi-rate-audio”, “public.mp3″, “public.au-audio”, “public.ac3-audio”}
  
repeat with aUTI in valList
    if (theWorkspace’s filenameExtension:aExt isValidForType:aUTI) as boolean then
      return (current application’s NSString’s stringWithString:aUTI)
    end if
  end repeat
  
error “Invalid Constant String”
end retFileFormatUTI

★Click Here to Open This Script 

AppleScript名:ムービー系の拡張子からFile Format UTIを取得する v3
– Created 2016-10-24 by Takaaki Naganoya
– Modified 2016-10-25 by Shane Stanley
– 2016 Piyomaru Software
use AppleScript version “2.4″
use framework “Foundation”
use framework “AVFoundation”
use scripting additions
use BridgePlus : script “BridgePlus” –Version 1.3.2以降
load framework

–http://piyocast.com/as/archives/4287

set aRes to retFileFormatUTI(“mov”) of me
–>  (NSString) “com.apple.quicktime-movie”

set aRes to retFileFormatUTI(“mp4″) of me
–>  (NSString) “public.mpeg-4″

set aRes to retFileFormatUTI(“m4v”) of me
–>  (NSString) “com.apple.m4v-video”

set aRes to retFileFormatUTI(“m4a”) of me
–>  (NSString) “com.apple.m4a-audio”

set aRes to retFileFormatUTI(“3gp”) of me
–>  (NSString) “public.3gpp”

set aRes to retFileFormatUTI(“3gp2″) of me
–>  (NSString) “public.3gpp2″

set aRes to retFileFormatUTI(“caf”) of me
–>  (NSString) “com.apple.coreaudio-format”

set aRes to retFileFormatUTI(“wav”) of me
–>  (NSString) “com.microsoft.waveform-audio”

set aRes to retFileFormatUTI(“aif”) of me
–>  (NSString) “public.aifc-audio”

set aRes to retFileFormatUTI(“aifc”) of me
–>  (NSString) “public.aifc-audio”

set aRes to retFileFormatUTI(“amr”) of me
–>  (NSString) “org.3gpp.adaptive-multi-rate-audio”

set aRes to retFileFormatUTI(“mp3″) of me
–>  (NSString) “public.mp3″

set aRes to retFileFormatUTI(“au”) of me
–>