Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

カテゴリー: Network

ChatGPTでchatに対する応答文を取得

Posted on 3月 6 by Takaaki Naganoya

OpenAIが提供しているREST APIを呼び出して、チャットに対する応答を生成するAppleScriptです。実行のためにはOpenAIのWebサイトにサインアップして、実行のためのAPI Keyを取得してください。

ChatGPTなどのサービスを提供しているOpenAIにサインアップして、各種サービスをAppleScriptから利用できます。Freeアカウントでは1分あたりに発行できるクエリー数の上限が低めに設定されていますが、実験を行う程度であれば十分なレベルでしょう。

https://platform.openai.com/docs/introduction

「chat」は、いわゆるChatGPTでよく知られている処理で、チャットに応答するものです。この呼び出し方に対して、さらにroleとして「system」「user」「assistant」などの役割を指定することで、チャットらしいやりとりを生成するようです(Chat completion)。

AppleScript名:Chat.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2023/03/05
—
–  Copyright © 2023 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property NSString : a reference to current application’s NSString
property NSCountedSet : a reference to current application’s NSCountedSet
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

set myText to "こんにちは"

set barerKey to "xx-XXXXXXXxXxxxxXxxXXxXXXXxxxXXxxxxXXxxxXXxXXxxXXxx"

set aText to "curl https://api.openai.com/v1/chat/completions -H ’Content-Type: application/json’ -H ’Authorization: Bearer " & barerKey & "’ -d ’{\"model\": \"gpt-3.5-turbo\",\"messages\": [{\"role\": \"user\", \"content\": \"" & myText & "\"}]}’"
set sRes to do shell script aText

set jsonString to NSString’s stringWithString:sRes
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
set aRes to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
set chatRes to (aRes’s valueForKeyPath:"choices.message.content") as list
–>{"こんにちは!こんにちはと言うと、こんにちはと返してくださる方が多いですね。私はAIアシスタントなので、いつでもお話し相手になれます。何かお話を聞かせてください。"}
–> {"、こんにちは! 私はAIアシスタントです。何かお手伝いできることはありますか?"}
–> {"こんにちは!私はAIアシスタントです。何かお手伝いできますか?"}
–> {"、私はAIアシスタントです。何かお手伝いできることはありますか?"}
–> {"こんにちは!こんにちはは、日本語で「こんにちは」と書き、挨拶の一つです。相手と会話をする際に使われる一般的な挨拶の言葉で、おはようございます、こんにちは、こんばんはなどがあります。どうぞよろしくお願いします!"}

★Click Here to Open This Script 

Posted in JSON Natural Language Processing Network REST API | Tagged 12.0savvy 13.0savvy ChatGPT | Leave a comment

LAN上のdaapクライアントの共有名をリストアップ v2

Posted on 5月 12, 2021 by Takaaki Naganoya

LAN上のdaap(Music/iTunesライブラリ共有)サービス名を検出するAppleScriptです。

LAN上の他のマシンで動作中のサービス名を収集します。AppleScriptを実行している自機のサービスは除外しています。

他のフォーラムへの無断転載、および転載時にもヘッダー部分を削除することを厳禁します。

AppleScript名:LAN上のdaapクライアントの共有名をリストアップ v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2021/05/11
—
–  Copyright © 2021 Piyomaru Software, All Rights Reserved
—   http://piyocast.com/as/
—
–  ** You are allowed to use this AppleScript with holding this header comment **
–  ** Don’t re-post this script to other forums without this header comment **
–  ** I’m very angry with removing header comment **

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property foundList : {}
property myHostNames : {}
property services : {}
property comingF : false
property resolveF : false

set mList to findHostsViaBonjour("_daap._tcp", "") of me
–> {"Takaaki Naganoya のライブラリ", "ぴよぴよ ライブラリ"}

on findHostsViaBonjour(aType as string, aDomain as string)
  set my foundList to {}
  
set my comingF to true
  
set my resolveF to false
  
set my myHostNames to (current application’s NSHost’s currentHost()’s names()) as list
  
–> {"MacMini2014.local", "macmini2014.local", "localhost"}
  
  
set aBrowser to current application’s NSNetServiceBrowser’s alloc()’s init()
  
aBrowser’s setDelegate:me
  
aBrowser’s searchForServicesOfType:aType inDomain:aDomain
  
  
repeat 100 times
    if my comingF = false then
      if my foundList is not equal to {} then exit repeat
    end if
    
delay 0.01
  end repeat
  
  
repeat 100 times
    if my resolveF = false then
      if my foundList is not equal to {} then exit repeat
    end if
    
delay 0.01
  end repeat
  
  
aBrowser’s setDelegate:(missing value)
  
return (my foundList)
end findHostsViaBonjour

–searchForServicesOfTypeのdelegate
on netServiceBrowser:aNetServiceBrowser didFindService:aNetService moreComing:aMoreComing
  copy (aMoreComing as boolean) to my comingF
  
set my resolveF to true
  
aNetService’s setDelegate:me
  
set cInfo to aNetService’s resolveWithTimeout:3
end netServiceBrowser:didFindService:moreComing:

–NetService’s resolveWithTimeoutのdelegate
on netServiceDidResolveAddress:aSender
  set cDesc to (aSender’s |name|()) as string
  
set dDesc to (aSender’s |hostName|()) as string
  
aSender’s |stop|() –すげー大事
  
  
set dDesc to repChar(dDesc, ".local.", ".local") of me
  
  
if dDesc is not in (my myHostNames) then
    set the end of (my foundList) to cDesc
  end if
end netServiceDidResolveAddress:

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

★Click Here to Open This Script 

Posted in Network | Tagged 10.14savvy 10.15savvy 11.0savvy NSHost NSNetService NSNetServiceBrowser | Leave a comment

歴史的大ニュース:Amazon AWSがMacインスタンスのサポートを開始

Posted on 12月 1, 2020 by Takaaki Naganoya

久しぶりに震えました。Amazon AWS(EC2)がMacのインスタンスをサポートしました(Amazon EC2 Mac instances)。

New – Use Amazon EC2 Mac Instances to Build & Test macOS, iOS, ipadOS, tvOS, and watchOS Apps

Amazon EC2 Mac InstancesDevelop, build, test, and sign Apple apps on Amazon EC2

このMacインスタンスは、通常のAWSとは異なりMac1台をまるまる占有するタイプのようです。ハードウェアはMac mini(Core i7 3.2GHz)でメモリ32GB。10Gbit Ethernet搭載モデルとのこと。

Amazon EC2 Mac InstancesがサポートするOSはmacOS 10.14と10.15、2021年にはM1 Mac miniの投入を検討しているのだとか。こちらはmacOS 11.x以降での運用になることでしょう。

利用者はTerminal上でSSHで接続するか、VNC Remote Desktop経由で接続することになるとのこと。XcodeでiOSなどのアプリケーションをビルドするための需要を見込んでいるようです。

「仮想マシンの1インスタンス時間貸し」というAWSのサービスイメージと大きく異なり、1台まるごと貸し出しサービスです。仮想化技術を用いて大量のインスタンスを同時実行する方向では、ライセンスの問題を解決できないことは明らかでしたが、逆に「こういう方法があったのか」というコロンブスの卵的な解決策ではあります。クラウドというよりは、時間貸しのコロケーションサービスともいえます。

最近のmacOSでは滅多にありませんが(のぞく、macOS 10.13と10.15)、OSごとまるごとクラッシュして再起動が必要になるとか、リセットが必要になるケースもないことはないでしょう。また、セキュリティ設定をユーザーが好き勝手にいじくれるかどうかも見所です(SIP解除して運用できるのかどうか、これは切実な問題です)。

Amazon EC2 Mac Instancesのサービス提供リージョンは、US East (N. Virginia), US East (Ohio), US West (Oregon), Europe (Ireland), and Asia Pacific (Singapore) とのことで、Tokyoは現段階ではありません。今後増えていくような書き方はされていますが、正直わかりません。

EC2というと、あらかじめディスクイメージを用意しておいて、インスタンスの起動をディスクイメージで実行、サービス運用と終了の必要な期間がきわめて短くて済むことを売りにしている印象があるものの、このAmazon EC2 Mac Instancesで運用するとどーなるのか。

利用料金をまだ確認できていないので、コロケーションサービス(初期費用が必要)に比べてどうなのかとか、実機まるごと買ったほうが安いんじゃないかとか、疑問はいろいろあるわけですが、REST APIのインタフェースだけ作ってしまえばクラウド上でAppleScriptによってサービスを作って提供できるわけで、ずいぶん悩ましい存在です。

AppleScript on the cloud的なサービスもできるし、仲間内で冗談でしか出てこなかった「Adobe Creative Grid」(時間貸しで大量のマシンによりAdobeアプリケーションのデータを高速かつ並列に処理する)みたいなサービスも作れてしまう(Adobe Createve Cloud税が高いのでむやみに実験はできないんですけれども)わけで、ずいぶん楽しい感じになってきました。

OS X 10.10で通常のAppleScriptからCocoaの機能が利用できるようになり、Cloud系のサービスを利用できるようになりました。機械学習系の機能も利用できています。

AppleScriptで大規模データとか超大量のデータ処理を行うさいの物理的な制約がなくなってきたわけで、数万人のユーザーへの一括メール送信とかいう無茶な処理も、外部のCloud(SendGrridなど)の機能を活用してできるようになりました(そこまで大量の送信は実際にはやっていないので、理論上最大値ということで)。

一方で、AppleScriptを使ってWebサービスそのものを作って運用するという方向には、ほとんど手が伸びていなかった状態です。外部でそのような需要が発生するか否かについては不明ですが、自分で作って自分で運営するサービスでは、柔軟に規模の拡大・縮小が行えることは重要です。

そうしたときに、外部とのI/FをRemote AppleEventで行うわけにはいかないでしょうし(AWSのデータセンターでポート3031へのリクエストが通るんだろか?)、一般的なREST APIでリクエストを受け付けてJSONで返すみたいな構造にする必要はあるでしょう。

あとは、並列処理技術。これまで、「Mac App Store向けのアプリケーションでは仕様上実装しづらい」ことから、それほど活躍の場がなかったAppleScriptによる並列処理技術ですが、外部からのリクエストを処理する場合には、とても必要になってくることでしょう。

やはり、実際にさわってみないとなんとも言えないですね。

Amazon EC2 Mac Instancesについて言及している記事一覧

Amazon Web Services ブログ 新登場 – Amazon EC2 Mac インスタンスを使用した macOS、iOS、ipadOS、tvOS、watchOS アプリの構築とテスト
もともとの記事の日本語版。サービス開始に向けた担当者の思いはわかるものの、費用とかmacOS環境でどのあたりがカスタマイズされているのか(ソフトウェア的に)とか、実際に使うとどの程度の差があるのかといった情報はない。Macユーザーに対して「Amazonは敵じゃないんだよー」と訴えている以上の情報はない

Amazon EC2 Mac Instance を早速使ってみました
EC2の使い方がわかる記事。これを読まないと接続までの手順がわかりづらいものの、これを読んだからといってMac Instanceの実情がわかるというほどの情報量はない

macOSがクラウドで利用可能に――、AWSがMac Miniベースの「Amazon EC2 Mac Instances」を一般提供開始

文章書きのプロがいい感じにまとめている。「よくわからない人」向けにまとめた記事

AWSにMacインスタンスが追加。6コアCore i7搭載Mac miniをクラウドで利用可能に

ニュースリリースまとめただけ。書くのに30分もかけていない速報記事(たぶん)

AWSがMac miniのクラウド化を発表、Apple Silicon Mac miniの導入は2021年初頭か

サービス料金面では一番詳細な記事。Amazon EC2 Mac Instancesは秒単位で課金されるが、最低利用ラインが「24時間」になっているため、24時間を過ぎたら秒単位で課金計算されるということが明記されている

Posted in Network news | Tagged 10.14savvy 10.15savvy 11.0savvy | Leave a comment

htmlの並列ダウンロード処理

Posted on 9月 13, 2019 by Takaaki Naganoya

Webコンテンツ(HTML)の並列ダウンロードを行うAppleScriptです。

Webコンテンツからデータを抽出する際に、あらかじめ一括でHTMLを並列ダウンロードしておいて、ダウンロードずみのデータを一括処理すると処理時間を大幅に短縮できます。「戦場の絆」Wikiから機体データの表をすべて取得するのに、順次HTMLを取得して抽出していた場合には3〜4分程度かかっていたものを、並列ダウンロードしたのちにデータ処理するように変更すれば、これが十数秒程度にまで高速化できます。

既存のプログラムを修正してHTMLのダウンロード用に仕立ててみました。並列キュー(未処理タスク数)へのアクセスはAppleScriptからはできなかった(実行すると結果が返ってこなかった)のですが、そこに手をつけずに並列処理の完了状態を検出しています。

ダウンロードが完了したデータはlist(配列)に入るので、リクエスト数と完了リクエスト数をループ内でチェックし、完了アイテム数がリクエスト数と同じになれば終了、条件を満たさない場合でも指定のタイムアウト時間を超えたらエラー終了という処理を行なっています。

問題点は、スクリプトエディタ上では実行できるもののScript Debugger上では実行できないことです(結果が返ってきません)。AppleScriptアプレットに書き出して実行してみたところ、結果が返ってきません。ただし、Script Menuからの実行は行えます(macOS 10.12.6、10.13.6、10.14.6で同様)。XcodeのAppleScript Appのプロジェクト内で実行することはできました。

このように、ランタイム環境に実行状況が左右される点にご注意ください。ただし、そうしたマイナス面を補ってあまりあるほどダウンロードは高速です。90ファイル強のダウンロードを数秒で完了(マシン、ネットワーク速度、ダウンロード先サーバーの負荷状況、キャッシュ状態などに左右される、参考値です)するため、ダウンロード後に各HTMLからのデータ抽出も高速に行えます。

AppleScript名:htmlの並列ダウンロード処理
— Created 2019-09-13 by Takaaki Naganoya
— 2019 Piyomaru Software
—
– オリジナル: HTTP からファイルをダウンロードして、ローカルに保存する方法(shintarou_horiのブログ)
— http://shintarou-hori.hatenablog.com/entry/2014/03/15/193604

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSData : a reference to current application’s NSData
property NSString : a reference to current application’s NSString
property NSOperationQueue : a reference to current application’s NSOperationQueue
property NSInvocationOperation : a reference to current application’s NSInvocationOperation
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

property aTimer : missing value

script spd
  property mList : {}
  
property resList : {}
end script

set (mList of spd) to {}
set (resList of spd) to {}
set baseURL to "https://w.atwiki.jp/senjounokizuna/pages/"

set numList to {25, 1594, 890, 70, 1669, 82, 1717, 997, 1080, 1614, 1712, 159, 1311, 1694, 1752, 1263}

set urlList to {}
repeat with i in numList
  set the end of urlList to (baseURL & i as string) & ".html"
end repeat

set aLen to length of urlList
set paramObj to {urls:urlList, timeOutSec:60}

–set (resList of spd) to downloadHTMLConcurrently(urlList, 60) of me
my performSelectorOnMainThread:"downloadHTMLConcurrently:" withObject:(paramObj) waitUntilDone:true
return length of (mList of spd)

on downloadHTMLConcurrently:paramObj
  set urlList to (urls of paramObj) as list
  
set timeOutS to (timeOutSec of paramObj) as real
  
set aLen to length of urlList
  
  
repeat with i in urlList
    set j to contents of i
    
set aURL to (|NSURL|’s URLWithString:j)
    
set aQueue to NSOperationQueue’s new()
    
set aOperation to (NSInvocationOperation’s alloc()’s initWithTarget:me selector:"execDL:" object:aURL)
    (
aQueue’s addOperation:aOperation)
  end repeat
  
  
–Check Completion
  
set compF to false
  
set loopTimes to (timeOutS * 10)
  
repeat loopTimes times
    if length of (mList of spd) = aLen then
      set compF to true
      
exit repeat
    end if
    
delay 0.1
  end repeat
  
  
if compF = false then error "Concurrent download timed out"
end downloadHTMLConcurrently:

on execDL:theURL
  set receiveData to NSData’s alloc()’s initWithContentsOfURL:theURL
  
if receiveData = missing value then
    return
  end if
  
  
set aFileName to theURL’s |lastPathComponent|()
  
my performSelectorOnMainThread:"saveData:" withObject:{receiveData, aFileName} waitUntilDone:false
end execDL:

on saveData:theDataArray
  copy theDataArray to {theData, saveFileName}
  
set aCon to NSString’s alloc()’s initWithData:theData encoding:NSUTF8StringEncoding
  
set the end of (mList of spd) to {fileName:saveFileName as string, contentsData:aCon as string}
end saveData:

★Click Here to Open This Script 

Posted in list Network URL | Tagged 10.12savvy 10.13savvy 10.14savvy NSData NSInvocationOperation NSOperationQueue NSString NSURL NSUTF8StringEncoding | Leave a comment

display youtube Script Libraryをアップデート

Posted on 9月 7, 2019 by Takaaki Naganoya

一発芸、出落ちと呼ばれた「display youtube」Script libraryをアップデート(v2.0)しました。

Download display youtube_v2.scptd (To ~/Library/Script Libraries/)

アップデート内容:
・AppleScript用語辞書内にサンプルScript(すぐに使えるScriptリンク内蔵)を掲載した
・start fromオプションを新設。再生開始位置を秒数で指定できるようにした
・エラーメッセージ内容をより親切にした

利用条件:
・YouTubeのムービーを視聴可能な程度のインターネット接続回線に接続していること
・macOS 10.11以降。実際の確認はmacOS 10.12以降。未確認ながら10.10上でも動作するはず

display youtubeライブラリの用語辞書を読むには、スクリプトエディタ上で、


▲「ウィンドウ」から「ライブラリ」を実行


▲「ライブラリ」パレットに「display youtube」ライブラリファイルをドラッグ&ドロップ。このライブラリパレット上のdisplay youtubeをダブルクリックすると用語辞書が表示されます


▲starts from無指定時(冒頭から再生)


▲starts from 24(冒頭から24秒の箇所から再生)


▲starts from 290(冒頭から290秒の箇所から再生)

YouTube上のオンラインゲームのリプレイムービーを視聴するような場合には、ムービー内容のうちスキップしたい場所とか「ここだけ見たい」という箇所は固定で決まっています(プログラムから書き出してYouTubeにアップロードするため)。そこで、再生開始ポジションを明示的に指定できると便利かと思われました。

ほかにも、いろいろと追加すると便利そうな機能はあります(未実装)。

いくつかボタンをダイアログ上に追加表示して、指定の秒数の箇所に頭出しするとか、表示内容のキャプチャーを撮るとかです(WkWebViewの表示内容を画像としてキャプチャする方法がぜんぜん不明。ウィンドウごとPDFとしてキャプチャしても撮れないし)。

コンピュータにスマホの機能で満足してしまうユーザーが多い昨今、ダイアログという箱庭的なUser Interface上にちょっとした便利機能を表示して使えるようにすると、それなりに満足できるユーザーが多いのではないかという仮説のもとに作成してみましたが、どんなもんでしょうか。

ちなみに、このリプレイムービーで自分はジオンの2番機でザクキャノンに搭乗。拠点を叩きつつ僚機にチャットで指示を送って、チームワークの力で勝利しました。

AppleScript名:display youtube sample
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/08/25
—
–  Copyright © 2019 jp.piyomarusoft, All Rights Reserved
—
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions
use utbLib : script "display youtube"

set aURL to "https://www.youtube.com/watch?v=GP_tVXTYdmY"
display youtube main message "Replay Movie" sub message "My Senjo No Kizuna replay movie on YouTube" with URL aURL with size {900, 600} starts from 24

★Click Here to Open This Script 

Posted in Network Script Libraries sdef URL | 1 Comment

display location Script Library

Posted on 8月 25, 2019 by Takaaki Naganoya

指定の緯度・経度情報の場所を4つの異なる表示倍率の地図でダイアログ表示するAppleScriptライブラリ+呼び出しサンプルです。

–> Download display location.scptd (To ~/Library/Script Libraries/)

サンプルScriptでは、指定のIPアドレスの位置情報をipinfo.io上で調べて表示しています。

本ライブラリは、掲載サンプルのように「display multiple map」コマンドを提供するもので、地図.appに頼らずにAppleScriptだけで簡単な地図表示UIを利用できるようにします。

AppleScript名:display location sample
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/08/25
—
–  Copyright © 2019 jp.piyomarusoft, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
use dispLoc : script "display location"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

set anIP to "193.228.57.200"
set locList to getGeoLocationByIPinfo(anIP) of me

display multiple map main message "侵略場所の表示" sub message "今回の地球侵略の目的地は、地球上の以下の場所になります" with location locList with size {900, 600}

–http://ipinfo.io/developers
on getGeoLocationByIPinfo(myIP)
  set aURL to "http://ipinfo.io/" & myIP
  
set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
  
  
if aRes = missing value then
    error "Network Error"
  end if
  
set aInfo to loc of aRes
  
set aPos to offset of "," in aInfo
  
set aLatitude to text 1 thru (aPos – 1) of aInfo
  
set aLongitude to text (aPos + 1) thru -1 of aInfo
  
  
return {aLatitude, aLongitude}
end getGeoLocationByIPinfo

on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set tmpData to (do shell script "curl -X GET \"" & reqURLStr & "\"")
  
set jsonString to NSString’s stringWithString:tmpData
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
if aJsonDict = missing value then return false
  
return (aJsonDict as record)
end callRestGETAPIAndParseResults

★Click Here to Open This Script 

Posted in geolocation GUI JSON Network sdef URL | Tagged 10.12savvy 10.13savvy 10.14savvy | Leave a comment

URLにリソースが存在するかチェック v5(NSURLSession)

Posted on 5月 24, 2019 by Takaaki Naganoya

指定URLの存在確認を行うAppleScriptです。

以前はNSURLConnectionを使って確認するものを使っていましたが、NSURLSessionへと移行しようかというところ。

もちろん、shellのcurlコマンドを使えば数行で済んでしまいますが、そこをあえてCocoaの機能を利用して、というよりはちょっと前に書いたREST API呼び出しのサブルーチンが絶好調で動いているので、これをそのまま流用してみました。

ライブラリ化して自分のScriptのバンドル内に入れておくとか、~/Library/Script Librariesフォルダに入れておくとか、そういう使い方になると思います。自分でもわざわざこれだけの機能のために、これだけの量のコードをゼロから書くことは……めったにありません。

AppleScript名:URLにリソースが存在するかチェック(curl版)_v2
set aURL to "http://www.apple.com/jp/"
set aRes to chekURLExistence(aURL) of me

on chekURLExistence(aURL)
  try
    set aRes to do shell script ("/usr/bin/curl -LI " & aURL)
  on error
    return false
  end try
  
return ((aRes contains "HTTP/1.1 200") or (aRes contains "HTTP/2 200")) as boolean
end chekURLExistence

★Click Here to Open This Script 

AppleScript名:URLにリソースが存在するかチェック v5(NSURLSession)
— Created 2019-05-24 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false

set aURL to "http://piyocast.com/as/"
set uRes to chekURLExistence(aURL) of me
–> true

on chekURLExistence(aURL as string)
  set webRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
return ((retCode of webRes) as integer = 200)
end chekURLExistence

— 指定URLにファイル(画像など)が存在するかチェック
–> {存在確認結果(boolean), レスポンスヘッダー(NSDictionary), データ(NSData)}
on callRestGETAPIAndParseResults(reqURLStr as string, timeOutSec as real)
  set (my retData) to false
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
set hitF to false
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeOutSec) times
    if (my drecF) = true then
      set hitF to true
      
exit repeat
    end if
    
delay ("0.001" as real)
  end repeat
  
  
if hitF = false then error "REST API Timeout Error"
  
  
return {retData:retData, retCode:retCode, retHeaders:retHeaders}
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  parseSessionResults(tmpSession, tmpTask, tmpData) of me
  
set (my drecF) to true
end URLSession:dataTask:didReceiveData:

–ないとエラーになるので足した。とくに何もしていない
on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  —
end URLSession:dataTask:willCacheResponse:completionHandler:

on parseSessionResults(aSession, aTask, tmpData)
  set aRes to aTask’s response()
  
set (my retCode) to aRes’s statusCode()
  
set (my retHeaders) to aRes’s allHeaderFields()
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set (my retData) to aJsonDict as anything
end parseSessionResults

★Click Here to Open This Script 

Posted in Network Record URL | Tagged 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableURLRequest NSString NSURL NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | Leave a comment

アラートダイアログ上に複数のNSBoxを作成してMKMapViewを表示

Posted on 3月 11, 2019 by Takaaki Naganoya

指定されたIPアドレスの位置情報(geo location)を検索して、アラートダイアログ上に拡大レベルの異なる4つの地図を表示するAppleScriptです。

IP Goecodingのサービスはipinfo.ioを利用しています。ただ、この手のサービスは入れ替わりが激しいので、長期的に使い続けられることを期待できないと感じています(有償サービスは別)。

このズームレベルが異なる地図の同時表示Viewは、作成したときには「これは画期的!」「ものすごく使いやすい!」と、狂喜乱舞したものですが、他のユーザーに見せてデモしたら、

「実際には限定されたエリア内の位置データを見ることが多いので、World LevelとかCountry Levelのビューは無駄なことが多い」
「地球を侵略しに来た異星人には向いているが、地球人向けには冗長」

といった意見が多く、オクラ入りしていました。アラートダイアログでさまざまなデータを可視化する部品の整備計画時に倉庫から引っ張り出されてきたものです。

唯一、IPアドレスという「見ただけではどこの国のものだかわからない」(Class AのIPは別。17.のAppleとか)データを可視化するときにはバッチリ合っています。

macOS 10.12〜10.14で確認していますが、唯一、macOS 10.14.4上では初期状態でピンが表示されません。ピン自体は存在しているので、地図表示タイプを変更すると表示されるのですが、一体これはどうしたものか。仕様なのかバグなのかわかりません。


▲なぜか本Blogにロス市警からのアクセスが(汗)


▲macOS 10.12.6 Map


▲macOS 10.12.6 Satellite


▲macOS 10.12.6 Map + Satellite


▲macOS 10.13.6 Map


▲macOS 10.14.4 Map (Light Mode)


▲macOS 10.14.4 Map (Dark Mode)

AppleScript名:アラートダイアログ上に複数のNSBoxを作成してMKMapViewを表示
— Created 2019-03-11 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "MapKit"
use framework "CoreLocation"

property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property MKMapView : a reference to current application’s MKMapView
property MKMapTypeHybrid : a reference to current application’s MKMapTypeHybrid
property MKPointAnnotation : a reference to current application’s MKPointAnnotation
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property MKMapTypeSatellite : a reference to current application’s MKMapTypeSatellite
property MKMapTypeStandard : a reference to current application’s MKMapTypeStandard
property NSSegmentedControl : a reference to current application’s NSSegmentedControl
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSSegmentStyleTexturedRounded : a reference to current application’s NSSegmentStyleTexturedRounded

property windisp : false
property selSeg : 0
property aMapViewList : {}

property segTitleList : {"Map", "Satellite", "Satellite + Map"}

property returnCode : 0

set aClip to the clipboard –このへんてきとう
set anIP to text returned of (display dialog "Input IP address to find its location" default answer aClip)

set windisp to false
set geoInfo to getGeoLocationByIPinfo(anIP) of me
if geoInfo = missing value then
  error "Network Error"
end if

set aInfo to loc of geoInfo

set aPos to offset of "," in aInfo
set aLatitude to text 1 thru (aPos – 1) of aInfo
set aLongitude to text (aPos + 1) thru -1 of aInfo

set aWidth to 1000
set aHeight to 600

set aButtonMSG to "OK"
set aMapViewList to {}

set paramObj to {viewWidth:aWidth, viewHeight:aHeight, viewTitle:anIP, viewSubTitle:"IP-Geocoding Service by ipinfo.io", viewLat:aLatitude, viewLong:aLongitude}

my performSelectorOnMainThread:"dispMapViewinDifferentScales:" withObject:(paramObj) waitUntilDone:true

on dispMapViewinDifferentScales:paramObj
  set aWidth to (viewWidth of paramObj) as real
  
set aHeight to (viewHeight of paramObj) as real
  
set aLat to (viewLat of paramObj) as real
  
set aLong to (viewLong of paramObj) as real
  
set aTitle to (viewTitle of paramObj) as string
  
set aSubTitle to (viewSubTitle of paramObj) as string
  
  
set selSeg to 0
  
  
–NSViewをつくる
  
set aView to current application’s NSView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
  
–各レベルのMapViewをBoxでつくる
  
set wList to {{3, "🌏World Level Map"}, {5, "🏰Country Level Map"}, {10, "🏢City Level Map"}, {17, "🏠Town Level Map"}}
  
set xPos to 0
  
repeat with i in wList
    copy i to {aLevelNum, aBoxTitle}
    
    
–Boxをつくる
    
set aBox to (current application’s NSBox’s alloc()’s initWithFrame:(current application’s NSMakeRect(xPos, 40, aWidth * 0.25, aHeight – 70)))
    (
aBox’s setTitle:aBoxTitle)
    
    
–MapView+Pinをつくる
    
set aMapView to makeMKMapView(aWidth * 0.25, aHeight – 70, aLevelNum, aLat, aLong, aTitle) of me
    
    (
aBox’s addSubview:aMapView)
    (
aView’s addSubview:aBox)
    
    
set the end of aMapViewList to aMapView
    
set xPos to xPos + (aWidth * 0.25)
  end repeat
  
  
–Segmented Controlをつくる
  
set aSeg to makeSegmentedControl(segTitleList, aWidth, aHeight) of me
  
aView’s addSubview:aSeg
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aTitle
    
its setInformativeText:aSubTitle
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
if (my returnCode as number) = 1001 then error number -128
end dispMapViewinDifferentScales:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

–MKMapViewをつくる
on makeMKMapView(aWidth, aHeight, aZoomLevel, aLat, aLong, aTitle)
  set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aMapView’s setMapType:(current application’s MKMapTypeStandard)
  
  
aMapView’s setZoomEnabled:true
  
aMapView’s setScrollEnabled:true
  
aMapView’s setPitchEnabled:false
  
aMapView’s setRotateEnabled:false
  
aMapView’s setShowsCompass:true
  
aMapView’s setShowsZoomControls:true
  
aMapView’s setShowsScale:true
  
aMapView’s setShowsUserLocation:true
  
  
set aLocation to current application’s CLLocationCoordinate2DMake(aLat, aLong)
  
aMapView’s setCenterCoordinate:aLocation zoomLevel:aZoomLevel animated:false
  
aMapView’s setDelegate:me
  
  
–MapにPinを追加
  
set anAnnotation to current application’s MKPointAnnotation’s alloc()’s init()
  
anAnnotation’s setCoordinate:aLocation
  
anAnnotation’s setTitle:aTitle
  
aMapView’s addAnnotation:anAnnotation
  
  
return aMapView
end makeMKMapView

–Make Segmented Control
on makeSegmentedControl(titleList, aWidth, aHeight)
  set aLen to length of titleList
  
  
set aSeg to NSSegmentedControl’s alloc()’s init()
  
aSeg’s setSegmentCount:aLen
  
  
set aCount to 0
  
repeat with i in titleList
    set j to contents of i
    (
aSeg’s setLabel:j forSegment:aCount)
    
set aCount to aCount + 1
  end repeat
  
  
aSeg’s setTranslatesAutoresizingMaskIntoConstraints:false
  
aSeg’s setSegmentStyle:(NSSegmentStyleTexturedRounded)
  
aSeg’s setFrame:(current application’s NSMakeRect(10, 5, 260, 30))
  
aSeg’s setTrackingMode:0
  
aSeg’s setTarget:me
  
aSeg’s setAction:"clickedSeg:"
  
aSeg’s setSelectedSegment:0
  
  
return aSeg
end makeSegmentedControl

–Segmented Control’s clicked event handler
on clickedSeg:aSender
  set aSel to aSender’s selectedSegment()
  
set selSeg to (aSel + 1)
  
set mapList to {MKMapTypeStandard, MKMapTypeSatellite, MKMapTypeHybrid}
  
set curMap to contents of item selSeg of mapList
  
  
repeat with i in aMapViewList
    set aView to contents of i
    (
aView’s setMapType:(curMap))
  end repeat
end clickedSeg:

–http://ipinfo.io/developers
on getGeoLocationByIPinfo(myIP)
  set aURL to "http://ipinfo.io/" & myIP
  
set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
  
return aRes as record
end getGeoLocationByIPinfo

on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set tmpData to (do shell script "curl -X GET \"" & reqURLStr & "\"")
  
set jsonString to NSString’s stringWithString:tmpData
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
if aJsonDict = missing value then return false
  
return (aJsonDict as record)
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to 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 (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to 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 

Posted in geolocation Network REST API | Tagged 10.11savvy 10.12savvy MKMapTypeHybrid MKMapTypeSatellite MKMapTypeStandard MKMapView MKPointAnnotation NSAlert NSJSONSerialization NSRunningApplication NSScreen NSSegmentedControl NSSegmentStyleTexturedRounded NSString NSUTF8StringEncoding | Leave a comment

(POST) Google Translate APIで翻訳

Posted on 12月 10, 2018 by Takaaki Naganoya

Google Translate API(REST API)を呼び出して、指定のテキストを別の言語に翻訳するAppleScriptです。

Google Cloud Consoleにお持ちのGoogleアカウントでログインし、プロジェクトを作成して、プロジェクト用のAPIを個別に許可(この場合にはGoogle Translate API)し、API Keyを発行してScript中に記述して呼び出します(retAPIKeyハンドラ中にハードコーディングするのが嫌であれば、Keychainに登録して呼び出すことも可能です)。

処理内容自体は、REST API呼び出しのいつものやつなんでとくに解説はしません。コピペで作れるぐらい退屈で簡単です(本Scriptも呼び出せることを確認するだけして放置していました)。

ただ、本Scriptは同期処理用のNSURLConnectionを使って呼び出しているバージョンで、このNSURLConnectionが将来的に廃止される見込みなので、curlコマンドで呼び出すか、NSURLSessionを使って呼び出すように書き換えるか、といったところです。

単体だとただ翻訳できるだけで、あまり面白味はありません。本ScriptはMicrosoft Azure Computer Vision APIで画像認識を行なったときに、その画像認識テキストが英文で返ってきており、その内容を日本語に自動翻訳するときに使用してみました。翻訳精度は悪くないと思うのですが、画像のシーン認識テキストの英文がいまひとつだったので、「英文で出力してくれた方がまだわかりやすい」というところで、個人的にはあまり活躍していません。

Translate APIを売り物の本の翻訳に使うことが許可されていないなど、利用許諾が割と厳しいので使いどころが多そうに見えつつもそうでもない、といったところでしょうか。

AppleScript名:(POST) Google Translate APIで翻訳
— Created 2016-03-03 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property NSString : a reference to current application’s NSString
property NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSURLConnection : a reference to current application’s NSURLConnection
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSURLComponents : a reference to current application’s NSURLComponents
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

set aSentense to "a birthday cake with lit candles"
set bSentense to retTranslatedString("en", "ja", aSentense) of me
–> "キャンドルライト付きの誕生日ケーキ"–Japanese

set cSentense to retTranslatedString("en", "de", aSentense) of me
–> "eine Geburtstagstorte mit brennenden Kerzen"–Deutsch

on retTranslatedString(fromLang, toLang, aSentense)
  set myAPIKey to retAPIKey() of me
  
set aRec to {|key|:myAPIKey, source:fromLang, |format|:"text", target:toLang, q:aSentense}
  
set aURL to "https://www.googleapis.com/language/translate/v2"
  
set bURL to retURLwithParams(aURL, aRec) of me
  
set aRes to callRestPOSTAPIAndParseResults(bURL) of me
  
  
set aRESCode to responseCode of aRes
  
if aRESCode is not equal to 200 then return ""
  
set aRESHeader to responseHeader of aRes
  
set aRESTres to (translatedText of (first item of translations of |data| of json of aRes)) as string
  
return aRESTres
end retTranslatedString

–POST methodのREST APIを呼ぶ
on callRestPOSTAPIAndParseResults(aURL)
  set aRequest to NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"POST"
  
aRequest’s setValue:"application/x-www-form-urlencoded" forHTTPHeaderField:"Content-Type"
  
  
set aRes to 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 NSString’s alloc()’s initWithData:bRes encoding:(NSUTF8StringEncoding)
  
  
set jsonString to NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to 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 retURLwithParams(aBaseURL, aRec)
  set aDic to 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 (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to 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 "XXxxXxXXXxXxX-XxXXxXXXxxxxXXXXxXxXXxXXX"
end retAPIKey

★Click Here to Open This Script 

Posted in JSON Network Record REST API Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableDictionary NSMutableURLRequest NSString NSURLComponents NSURLConnection NSURLQueryItem NSUTF8StringEncoding | Leave a comment

teratailの指定IDのユーザー情報を取得する_curl

Posted on 11月 27, 2018 by Takaaki Naganoya

プログラミング系質問サイトteratailのREST APIを呼び出して、指定ユーザー名の情報を取得するAppleScriptです。

TeratailのREST APIは、タグ、ユーザー、質問の3ジャンルの情報取得を行えるように整備されており、特定カテゴリ(タグで分類)の新規質問が投稿されたかどうかを定期的に確認するようなAppleScriptを作って運用することもできます(そこまでやっていないですけれども)。

REST API呼び出しにはNSURLConnectionからNSURLSessionに移行していますが、どうもNSURLSessionだと呼び出せない(AppleScriptからの呼び出し処理が完了しない)サービスがあったりするので、結局shellのcurlコマンドを呼び出すのが手短にすむケースが多いようです。

Teratailの場合も、NSURLSessionで呼び出せるAPIもあれば、結果が返ってこないAPIもあり、NSURLConnectionよりも使い勝手がよくないと感じています(個人の感想です)。

このあたり、将来的なmacOSのアップデートでNSURLConnectionが使えなくなる日が来るのかもしれませんが、curlコマンドを使うように集約するべきなのか、NSURLSessionで書き換えるべきなのか悩ましいところです。

AppleScript名:teratailの指定IDのユーザー情報を取得する_curl
— Created 2018-11-26 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSURLComponents : a reference to current application’s NSURLComponents
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

set aUserRes to searchOneUserByDisplayName("Piyomaru") of me
–> {meta:{limit:20, message:"success", hit_num:1, total_page:1, page:1}, users:{{score:43, photo:"https://teratail.storage.googleapis.com/uploads/avatars/u6/66639/MSIS21by_thumbnail.jpg", display_name:"Piyomaru"}}}

on searchOneUserByDisplayName(aName)
  set aRec to {q:aName}
  
set reqURLStr to "https://teratail.com/api/v1/users/search"
  
set bURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set tmpData to (do shell script "curl -X GET \"" & bURL & "\"")
  
set jsonString to NSString’s stringWithString:tmpData
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
if aJsonDict = missing value then return false
  
return (aJsonDict as record)
end searchOneUserByDisplayName

on retURLwithParams(aBaseURL, aRec)
  set aDic to 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 (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to 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 

Posted in Network Record REST API shell script URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableDictionary NSString NSURL NSURLComponents NSURLQueryItem | 1 Comment

ftpKitのじっけん ftpサーバーからファイル一覧を取得

Posted on 11月 3, 2018 by Takaaki Naganoya

オープンソースのFTPManagerをフレームワーク化したftpKitを利用して、指定サーバー上の指定ディレクトリ内のファイル一覧を取得するAppleScriptです。

sftp接続が必要な場合にはTransmitをAppleScriptからコントロールすることになるわけですが、セキュリティ的にあまり問題にならない用途であればFTP経由でファイル転送することもあるでしょう。

AppleScript名:ftpKitでファイル一覧を取得
— Created 2016-03-01by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "ftpKit" –https://github.com/nkreipke/FTPManager

set serverURL to "ftp://www.piyocast.com/xxxxx/public_html/private"
set serverUser to "xxxxx@piyocast.com"
set serverPassword to text returned of (display dialog "Input FTP Password" default answer "" with hidden answer)

set aFtpManager to current application’s FTPManager’s alloc()’s init()
set successF to false

set srv to current application’s FMServer’s serverWithDestination:serverURL username:serverUser |password|:serverPassword
srv’s setPort:21

set aResList to aFtpManager’s contentsOfServer:srv

set fileNameList to {}
set fileCount to aResList’s |count|()

repeat with i from 0 to (fileCount – 1)
  set anItem to (aResList’s objectAtIndex:i)
  
  
set aFileName to (anItem’s valueForKeyPath:"kCFFTPResourceName") as string
  
set the end of fileNameList to aFileName
end repeat

fileNameList
–>  {".", "..", "xls1a.png", "xls3.png"}

★Click Here to Open This Script 

Posted in file Network | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

WordPressの指定IDの記事にリンクされているapplescriptからCocoa Classのproperty宣言を抽出

Posted on 7月 30, 2018 by Takaaki Naganoya

WordPressで稼働しているBlog(AppleScriptの穴)の、指定記事IDの本文を取得し、本文内でリンクしているURLのうち指定schemeのものを抽出し、URLリンクされているAppleScriptのソースをデコードしてproperty宣言文のうちCocoa Classの宣言を行っているものを抽出するAppleScriptです。

HTMLReader.frameworkを用いてBlog本文からのリンク抽出、リンクURL抽出を行っています。

–> HTMLReader.framework(To ~/Library/Frameworks/)

本Blogで、Tagの運用を変更しようと思い立ち、手作業で修正をはじめました。アプリケーション名のほかにCocoa Class名をTagにしようという試みです。

ただ、数個の記事のTag付け直しを行っただけで「手作業では終わらない」ことが判明。2月に再構築をはじめて1,000本ぐらいの記事をアップしているので、手作業ではとても無理です

本Blogの記事にURLリンクされているAppleScriptソースプログラムを(XML-RPC経由で)AppleScriptから自動で取得し、

その中のproperty宣言文を抽出して、

Cocoa Classの宣言文のみをリストアップして、

Blog記事のTagに自動で指定できないか、と試してみたものです。

現時点で、

  (1)指定Blog記事の本文を取得
  (2)(1)から指定URL SchemeのリンクURLを抽出
  (3)(2)のURL EncodeされているAppleScriptソースをDecode
  (4)property宣言文のみ抽出
  (5)property宣言ラベルがCocoa Classのものかをチェックして抽出

というところまでできています。本プログラムは、BlogのUser NameとPasswordが必要なので、リストのまま動かしてもエラーになり動作しません。同様にWordPressで運用されているBlogがあれば、そちらで試してみるのもよいでしょう。

XML-RPCでWordPressと通信するのには、記事アップロード自動化に使ったFrameworkもありますが、ためしにAppleScript標準搭載のcall xmlrpcコマンドを使ってみました。記事新規投稿コマンドだとクラッシュを起こしますが、この程度の用途ならクラッシュせずに使えるようです。

また、property文の抽出は構文要素を考慮していないため、コメントアウトされているものも拾ってくる可能性があります(単に行頭のproperty宣言文を拾っているだけなので、複数行コメントになっているものは拾われてくることでしょう)。

(*
property NSArray: a reference to current application’s NSArray
property NSString: a reference to current application’s NSString
*)

これを防ぐために、URLリンクされたAppleScriptをデコードした後で、いったんAppleScriptとして構文確認(コンパイル)を実施して、実際のAppleScriptとして評価すべきなのでしょう。

AppleScript名:WordPressの指定IDの記事にリンクされているapplescriptからCocoa Classのproperty宣言を抽出 v2
— Created 2018-07-30 by Takaaki Naganoya
— Modified 2018-07-31 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSBundle : a reference to current application’s NSBundle
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

–PostID
set postID to 3826
set aScheme to "applescript://"

–WordPressの指定Post IDの記事を取得してリンクされているURLからURL Schemeでフィルタして、リンクされているAppleScriptのソースを
–取得し、AS Sourceからproperty宣言文のみ抽出
set pList to getASSouceLinkedInWordPressPost(postID, aScheme) of me
–>  {"property NSBundle : a reference to current application’s NSBundle", "property |NSURL| : a reference to current application’s |NSURL|", "property HTMLDocument : a reference to current application’s HTMLDocument", "property NSMutableDictionary : a reference to current application’s NSMutableDictionary", "property NSPredicate : a reference to current application’s NSPredicate", "property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding", "property NSMutableSet : a reference to current application’s NSMutableSet", "property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch", "property NSString : a reference to current application’s NSString", "property NSSortDescriptor : a reference to current application’s NSSortDescriptor"}

–property宣言文リストから、propetyがCocoa Classの宣言であるものだけを抽出
set p2List to filterPropertySentenseWhetherCocoaOrNot(pList) of me
–>  {"NSBundle", "HTMLDocument", "NSMutableDictionary", "NSPredicate", "NSMutableSet", "NSString", "NSSortDescriptor"}

on filterPropertySentenseWhetherCocoaOrNot(pList)
  set outList to {}
  
  
repeat with i in pList
    set j to contents of i
    
set j2 to repChar(j, "|", "") of me
    
    
–Parse String Into Words by Space
    
set aTmpStr to (NSString’s stringWithString:j2)
    
set wList to (aTmpStr’s componentsSeparatedByString:" ") as list
    
    
if wList contains {"a", "reference", "to", "current", "application’s"} then
      –通常のクラス名の場合(クラス名以外のpropertyの場合もある)
      
set aTarg to contents of item 2 of wList
      
      
–property値がCocoa Classかどうかを判定    
      
set fRes to searchClassInFrameworks(aTarg) of me
      
      
if fRes is not equal to false then
        set the end of outList to aTarg
      end if
    end if
  end repeat
  
  
return outList
end filterPropertySentenseWhetherCocoaOrNot

–指定クラスがいずれかのCocoa Frameworkに所属しているかを検索
on searchClassInFrameworks(aTarget)
  set aClass to current application’s NSClassFromString(aTarget)
  
if aClass = missing value then return false
  
set theComponenents to (NSBundle’s bundleForClass:aClass)’s bundleURL’s pathComponents()
  
set thePred to NSPredicate’s predicateWithFormat:"pathExtension == ’framework’"
  
set aRes to (theComponenents’s filteredArrayUsingPredicate:thePred)’s firstObject() as list of string or string
  
return aRes
end searchClassInFrameworks

–指定Post IDのWordPress記事から、指定SchemeのURLを抽出し、AS Sourceをdecodeしてproperty行のみ抽出
on getASSouceLinkedInWordPressPost(postID, aScheme)
  set {myUser, myPass} to getAcountData() of me
  
  
tell application "http://piyocast.com/as/xmlrpc.php"
    set wRes to (call xmlrpc {method name:"wp.getPost", parameters:{"1", myUser, myPass, postID as string}})
  end tell
  
set aBody to post_content of wRes –Blog本文
  
  
–記事中でリンクしているURLを取得し、指定のURL Schemeでフィルタする
  
set urlList to filterURLLinksByScheme(aBody, aScheme) of me
  
  
set propList to {}
  
  
repeat with i in urlList
    set j to contents of i
    
set urlRec to parseQueryDictFromURLString(j) of me
    
set tmpScript to (urlRec’s |script|) as string –Get AppleScript Source
    
    
set tList to paragraphs of tmpScript
    
set pList to filterListUsingPredicate(tList, "SELF BEGINSWITH[c] %@", "property") –後方一致
    
    
set propList to propList & pList
  end repeat
  
  
return propList
end getASSouceLinkedInWordPressPost

on filterListUsingPredicate(aList as list, aPredicateStr as string, targStr as string)
  set setKey to current application’s NSMutableSet’s setWithArray:aList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat_(aPredicateStr, targStr)
  
set aRes to (setKey’s filteredSetUsingPredicate:aPredicate)
  
set bRes to aRes’s allObjects()
  
set cRes to bRes as {list, list of string or string}
  
return cRes
end filterListUsingPredicate

on parseQueryDictFromURLString(aURLStr as string)
  if aURLStr = "" then error "No URL String"
  
  
set aURL to |NSURL|’s URLWithString:aURLStr
  
set aQuery to aURL’s query() –Get Query string part from URL
  
if aQuery’s |length|() = 0 then return false
  
  
set aDict to NSMutableDictionary’s alloc()’s init()
  
set aParamList to (aQuery’s componentsSeparatedByString:"&") as list
  
  
repeat with i in aParamList
    set j to contents of i
    
if length of j > 0 then
      set tmpStr to (NSString’s stringWithString:j)
      
set eList to (tmpStr’s componentsSeparatedByString:"=")
      
set anElement to (eList’s firstObject()’s stringByReplacingPercentEscapesUsingEncoding:(NSUTF8StringEncoding))
      
set aValStr to (eList’s lastObject()’s stringByReplacingPercentEscapesUsingEncoding:(NSUTF8StringEncoding))
      (
aDict’s setObject:aValStr forKey:anElement)
    end if
  end repeat
  
  
return aDict
end parseQueryDictFromURLString

–指定のHTML文字列から、Link URLを抽出し、schemeで再抽出する
on filterURLLinksByScheme(aBody, aScheme)
  set conType to "text/html"
  
  
–HTML文字列をいったんNSDataにしているのは、HTMLReader.frameworkの仕様のため
  
set aData to (current application’s NSString’s stringWithString:aBody)’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aHTML to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType
  
  
set aTextArray to ((aHTML’s nodesMatchingSelector:"a")’s textContent) as list –リンク文字
  
set aLinkList to ((aHTML’s nodesMatchingSelector:"a")’s attributes’s valueForKeyPath:"href") as list –URL文字列
  
  
set outList to {}
  
repeat with i in aLinkList
    set j to contents of i
    
if j begins with aScheme then
      set the end of outList to j
    end if
  end repeat
  
  
return outList
end filterURLLinksByScheme

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

on getAcountData()
  return {"xxxxxxxx_xx", "XXXXXXXXXXXXXXXXXXXXXXXX"}
end getAcountData

★Click Here to Open This Script 

Posted in list Network Record URL XML-RPC | Tagged 10.11savvy 10.12savvy 10.13savvy NSArray NSBundle NSString NSURL | Leave a comment

Recruit Tech Japanese Proofreading API

Posted on 6月 26, 2018 by Takaaki Naganoya

Recruit techのA3RT機械学習ソリューションAPIのひとつ、「Proofreading API」(日本語文章校正API)を呼び出すAppleScriptです。

APIの説明ページからAPI Keyを取得して本リストに記載して実行させてみてください。

「とりあえず作ってみました」レベルで実用性については皆無です。誤変換を指摘できるという触れ込みなのですが、助詞の多重入力、誤変換などほとんど見落としてくれます。

日本語の新語作成能力が高いのと、日本語自体がわりとずさんな運用が行われているといった事情もあり、日本語スペルチェックで完全なものを作れると言い切るには勇気が必要です。

日本語文章のスペルチェックという目的自体が壮大すぎて、実用レベルまで持っていくこと自体が大変です。ある程度の「割り切り」が必要になってくるものと思われます。ただ、このAPIがどういう割り切りを行なったのかが見えてきません、、、

AppleScript名:Recruit Tech Japanese Proofreading API
— Created 2018-06-13 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
–https://a3rt.recruit-tech.co.jp/product/proofreadingAPI/

set apiKeyStr to getAPIKey() of me
set targText to returnBody() of me
set sensitivity to "high"

set sText to "curl -X POST -d ’apikey=" & apiKeyStr & "’ –data-urlencode ’sentence=" & targText & "’ ’sensitivity=" & sensitivity & "’ ’https://api.a3rt.recruit-tech.co.jp/proofreading/v2/typo’"
set aRes to do shell script sText
set jsonString to current application’s NSString’s stringWithString:aRes
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)
set aRec to aJsonDict as record
–>  {resultID:"0dee57af118a", status:1, inputSentence:"本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表貝でさた。", normalizedSentence:"本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表貝でさた。", alerts:{{|word|:"貝", suggestions:{"ま", "会", "す"}, score:1.0, pos:41}}, message:"pointed out", checkedSentence:"本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表 <<貝>> でさた。"}

on getAPIKey()
  return "XXXXxXxxXXXxXXXxxxXXxxXXxXXXXXXx"
end getAPIKey

on returnBody()
  return "本来はハードウェア製品のの発表のの場ではなくて、OSなどのソフトベアの話をする発表貝でさた。"
end returnBody

★Click Here to Open This Script 

Posted in Network REST API Text | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Recruit Tech Small Talk API

Posted on 6月 25, 2018 by Takaaki Naganoya

Recruit techのA3RT機械学習ソリューションAPIのひとつ、「Small Talk API」を呼び出すAppleScriptです。

エンタメ用に機械学習させたお手軽日本語チャットボット作成用のAPIとのこと。APIの説明ページからAPI Keyを取得して本リストに記載して実行させてみてください。

「おはよう」に「おはよう」で返したり、質問に質問で返すような「使えないチャットボットAPI」ですが、雑談系チャットボットに過剰な期待をするのは間違いなので、こんなもんなんでしょう。

AppleScript名:Recruit Tech Talk API
— Created 2018-06-13 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set apiKeyStr to getAPIKey() of me
set targText to text returned of (display dialog "Input Some text" default answer "")

set sText to "curl -X POST -d ’apikey=" & apiKeyStr & "’ –data-urlencode ’query=" & targText & "’ ’https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk’"
set aRes to do shell script sText
set jsonString to current application’s NSString’s stringWithString:aRes
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)
set aRec to aJsonDict as record
–>  {​​​​​status:0, ​​​​​message:"ok", ​​​​​results:{​​​​​​​{​​​​​​​​​perplexity:0.834903951818, ​​​​​​​​​reply:"何の事でしょう?"​​​​​​​}​​​​​}​​​}
–>  {​​​​​status:2000, ​​​​​message:"empty reply"​​​}

set curStat to status of aRec
if curStat is not equal to 0 then return false
set theAns to (aJsonDict’s valueForKeyPath:"results.reply") as list of string or string
say theAns using "Otoya" –"Kyoko" or "Otoya"

on getAPIKey()
  return "XXXXxxxXxxXXXxXXXxXxxXXxxxXxXxXX"
end getAPIKey

★Click Here to Open This Script 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Call Postmark’s spam detection API

Posted on 6月 21, 2018 by Takaaki Naganoya

PostmarkのSpamAssassin REST APIを呼び出してメールのスパム判定を行うAppleScriptです。

NSURLSessionを用いてPOST methodのREST APIを呼び出しています。

メール本文のソーステキストを渡すと、スパム度のスコアを計算して返してくれます。パラメータの「options」で「short」か「long」を指定でき、最終的な評価値のみ知りたい場合には前者を、詳細情報を知りたい場合には後者を指定することになります。

すでにMail.appにスパム判定の機能が標準搭載されているため、スパムフィルタ単体で利用する用途というのは減ってきましたが、メールの送信前にスパムフィルタに引っかからないかをチェックしておく(メールマガジン作成時など)ためには「あったほうが便利」な処理です。

本APIを利用するのに、事前のユーザー登録やAPI Keyを取得する必要はありません。このリストを実行するとそのまま結果が得られます。Mail.appのメッセージのソースを渡すのもたいして手間はかかりません。

ただし、本APIは継続して提供される保証もありませんし、トラブルが発生して動作が止まっていた場合に対処してくれたりはしません。実際の業務ほかシビアな用途で利用するのはためらわれるものがあります。

ローカルにSpamSieveをインストールしてAppleScriptで呼び出すと同様にスパム評価値を計算してくれるので、メールのSPAM判定のための用途にはこれも検討に値するでしょう。

AppleScript名:Call Postmark’s spam API
— Created 2018-06-20 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0

set aBody to "raw dump of email"

–https://spamcheck.postmarkapp.com/doc/
set aURL to "https://spamcheck.postmarkapp.com/filter"
set aRec to {email:aBody, options:"long"}

set aRESTres to callRestPOSTAPIAndParseResults(aURL, aRec, 10) of me
set aRESTcode to retCode of aRESTres
–> 200

set aRESTheader to retHeaders of aRESTres
set aRESTres to retData of aRESTres
–> {success:true, rules:{{score:"1.2", |description|:"Missing To: header"}, {score:"-0.0", |description|:"Informational: message was not relayed via SMTP"}, {score:"1.4", |description|:"Missing Date: header"}, {score:"1.8", |description|:"Missing Subject: header"}, {score:"2.3", |description|:"Message appears to have no textual parts and no Subject: text"}, {score:"0.1", |description|:"Missing Message-Id: header"}, {score:"-0.0", |description|:"Informational: message has no Received headers"}, {score:"1.0", |description|:"Missing From: header"}, {score:"0.0", |description|:"Message appears to be missing most RFC-822 headers"}}, score:"7.9", report:" …."}

on callRestPOSTAPIAndParseResults(reqURLStr as string, aRec as record, timeoutSec as integer)
  set retData to missing value
  
set retCode to 0
  
set retHeaders to {}
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"POST"
  
aRequest’s setCachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData)
  
aRequest’s setHTTPShouldHandleCookies:false
  
aRequest’s setTimeoutInterval:timeoutSec
  
–aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"–Does not work with this API & Method
  
aRequest’s setValue:"application/json" forHTTPHeaderField:"Accept"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set dataJson to current application’s NSJSONSerialization’s dataWithJSONObject:aRec options:0 |error|:(missing value)
  
aRequest’s setHTTPBody:dataJson
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
set hitF to false
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if retData is not equal to missing value then
      set hitF to true
      
exit repeat
    end if
    
delay ("0.001" as real)
  end repeat
  
  
if hitF = false then error "REST API Timeout Error"
  
  
return {retData:retData, retCode:retCode, retHeaders:retHeaders}
end callRestPOSTAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  set aRes to tmpTask’s response()
  
set retCode to aRes’s statusCode()
  
set retHeaders to aRes’s allHeaderFields()
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set retData to aJsonDict as list of string or string –as anything
end URLSession:dataTask:didReceiveData:

★Click Here to Open This Script 

Posted in JSON Network Record REST API URL | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

GET method REST API v4.1

Posted on 6月 17, 2018 by Takaaki Naganoya

Web上のREST APIを、NSURLSessionを用いて呼び出すAppleScriptの改良版です。

status code、Response Header、処理結果をそれぞれ返すように改良してみました。これで、実際のプログラムに組み込むことができるようになりました。

Response Headerの各フィールドはスペースやハイフンを含んでいたりするので、CocoaのNSDictionaryからAppleScriptのrecordに変換すると値が取り出せなくなってしまいます。

そのため、NSDictionaryのまま返すようにしています。

AppleScript名:GET method REST API v4.1
— Created 2018-06-16 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0

set reqURLStr to "http://jsonplaceholder.typicode.com/posts"
set aRESTres to callRestGETAPIAndParseResults(reqURLStr, 10) of me
set aRESTcode to retCode of aRESTres
–> 200

set aRESTheader to retHeaders of aRESTres
–>  (NSDictionary) {​​​​​Content-Type:"application/json; charset=utf-8", ​​​​​Pragma:"no-cache", ​​​​​X-Powered-By:"Express", ​​​​​Set-Cookie:"__cfduid=dc7a11359ba7f9518366108f4c2e2d7fb1529215907; expires=Mon, 17-Jun-19 06:11:47 GMT; path=/; domain=.typicode.com; HttpOnly", ​​​​​Server:"cloudflare", ​​​​​Via:"1.1 vegur", ​​​​​Content-Encoding:"gzip", ​​​​​Expires:"Sun, 17 Jun 2018 15:21:12 GMT", ​​​​​CF-Cache-Status:"HIT", ​​​​​Transfer-Encoding:"Identity", ​​​​​Cache-Control:"public, max-age=14400", ​​​​​Date:"Sun, 17 Jun 2018 11:21:12 GMT", ​​​​​Access-Control-Allow-Credentials:"true", ​​​​​Connection:"keep-alive", ​​​​​CF-RAY:"42c5219eb6f2a5cc-NRT", ​​​​​Etag:"W/"6b80-Ybsq/K6GwwqrYkAsFxqDXGC7DoM"", ​​​​​Vary:"Origin, Accept-Encoding", ​​​​​X-Content-Type-Options:"nosniff"​​​}

set aRESTres to retData of aRESTres
–>
(*
{​​​​​{​​​​​​​body:"quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto", ​​​​​​​id:1, ​​​​​​​title:"sunt aut facere repellat provident occaecati excepturi optio reprehenderit", ​​​​​​​userId:1​​​​​},….}
*)

on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set retData to missing value
  
set retCode to 0
  
set retHeaders to {}
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
set hitF to false
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if retData is not equal to missing value then
      set hitF to true
      
exit repeat
    end if
    
delay ("0.001" as real)
  end repeat
  
  
if hitF = false then error "REST API Timeout Error"
  
  
return {retData:retData, retCode:retCode, retHeaders:retHeaders}
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  set aRes to tmpTask’s response()
  
set retCode to aRes’s statusCode()
  
set retHeaders to aRes’s allHeaderFields()
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set retData to aJsonDict as list of string or string –as anything
end URLSession:dataTask:didReceiveData:

★Click Here to Open This Script 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

GET method REST API v4

Posted on 6月 17, 2018 by Takaaki Naganoya

Web上のREST APIを、NSURLSessionを用いて呼び出すAppleScriptです。

各種REST APIをAppleScriptから呼び出して使うのは、もはや日常的な光景になっていますが、これまでNSURLConnectionを用いていたのが気になっていました。

現在の、Cocoa-BridgeされたAppleScriptではObjective-CのBlocks構文を用いるAPIを呼び出せないために、非同期処理ではなく同期処理を用いる必要があります。NSURLConnectionは明示的に同期処理を呼び出すことができますが、NSURLSessionのサンプルではもれなくBlocks構文が書かれていたので、使えないものかと思っていました。

ただ、それは私・長野谷の単なる思い込みであり、Xcodeでヘッダーファイルを調べてみたらBlocks構文を使わずに書けることがわかったので試してみたものです。呼び出しているのは動作確認用のREST APIで、毎回同じ値を返してきます。

まだ、status codeを受け取れていないので実際の処理に組み込むことはできませんが、きちんと動くコードが書けた意義は大きいでしょう。

AppleScript名:GET method REST API v4
— Created 2018-06-16 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value

set retData to missing value

set reqURLStr to "http://jsonplaceholder.typicode.com/posts"
set aRESTres to callRestGETAPIAndParseResults(reqURLStr) of me
–>  
(*
{​​​​​{​​​​​​​body:"quia et suscipit
suscipit recusandae consequuntur expedita et cum
reprehenderit molestiae ut ut quas totam
nostrum rerum est autem sunt rem eveniet architecto", ​​​​​​​id:1, ​​​​​​​title:"sunt aut facere repellat provident occaecati excepturi optio reprehenderit", ​​​​​​​userId:1​​​​​}, ​​​​​{​​​​​​​body:"est rerum tempore vitae
sequi sint nihil reprehenderit dolor beatae ea dolores neque
fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis"}……}
*)

on callRestGETAPIAndParseResults(reqURLStr)
  set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat 10000 times
    if retData is not equal to missing value then exit repeat
    
delay ("0.001" as real)
  end repeat
  
  
retData
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  set aStat to (tmpTask’s state()) as list of string or string
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
set retData to aJsonDict as list of string or string
end URLSession:dataTask:didReceiveData:

★Click Here to Open This Script 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Twitterで指定アカウントのタイムラインを取得

Posted on 3月 30, 2018 by Takaaki Naganoya
AppleScript名:Twitterで指定アカウントのタイムラインを取得
— Created 2016-11-22 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

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) as list of string or string
–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 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Twitterでフォロワーリストの情報を取得する

Posted on 3月 30, 2018 by Takaaki Naganoya
AppleScript名:Twitterでフォロワーリストの情報を取得する
— Created 2016-11-22 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set myConsumerKey to "xXXXXXXXxxXXxXxxxXXxXxXXX"
set myConsumerSecret to "xxxxXXXxXxXXXxXXXxxxXXXXXxxXxxXXXxXXXxxXXxxxXXxxXx"

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

set nextCursor to "0"
set allFolList to current application’s NSMutableArray’s new()

–実際のAPI呼び出し
set reqURLStr to "https://api.twitter.com/1.1/followers/list.json"

repeat 100 times
  if nextCursor = "0" then
    set bRec to {|count|:"200", screen_name:"Piyomaru"}
  else
    set bRec to {|count|:"200", cursor:nextCursor, screen_name:"Piyomaru"}
  end if
  
  
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 followerList to (aRESTres’s valueForKeyPath:"users") as list
  
allFolList’s addObjectsFromArray:followerList
  
set nextCursor to aRESTres’s valueForKeyPath:"next_cursor_str"
  
  
if (nextCursor as string) = "0" then exit repeat
end repeat

return allFolList

–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 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Twitterでフォロワーリストの情報を取得して作成日とscreen_nameを抽出して最終Tweet日を取得

Posted on 3月 30, 2018 by Takaaki Naganoya
AppleScript名:Twitterでフォロワーリストの情報を取得して作成日とscreen_nameを抽出して最終Tweet日を取得
— Created 2016-11-22 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set myConsumerKey to "xXXXXXXXxxXXxXxxxXXxXxXXX"
set myConsumerSecret to "xxxxXXXxXxXXXxXXXxxxXXXXXxxXxxXXXxXXXxxXXxxxXXxxXx"

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

set nextCursor to "0"
set allFolList to current application’s NSMutableArray’s new()

–実際のAPI呼び出し
set reqURLStr to "https://api.twitter.com/1.1/followers/list.json"

repeat 100 times
  if nextCursor = "0" then
    set bRec to {|count|:"200", screen_name:"Piyomaru"}
  else
    set bRec to {|count|:"200", cursor:nextCursor, screen_name:"Piyomaru"}
  end if
  
  
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 followerList to (aRESTres’s valueForKeyPath:"users") as list
  
allFolList’s addObjectsFromArray:followerList
  
set nextCursor to aRESTres’s valueForKeyPath:"next_cursor_str"
  
  
if (nextCursor as string) = "0" then exit repeat
end repeat

–return allFolList
set creList to (allFolList’s valueForKeyPath:"created_at") as list of string or string
set idList to (allFolList’s valueForKeyPath:"id_str") as list of string or string
set scNameList to (allFolList’s valueForKeyPath:"screen_name") as list of string or string

–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 

Posted in Network REST API | Tagged 10.11savvy 10.12savvy 10.13savvy | Leave a comment

Post navigation

  • Older posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • macOS 13, Ventura(継続更新)
  • アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v3
  • UI Browserがgithub上でソース公開され、オープンソースに
  • macOS 13 TTS Voice環境に変更
  • Xcode 14.2でAppleScript App Templateを復活させる
  • 2022年に書いた価値あるAppleScript
  • ChatGPTで文章のベクトル化(Embedding)
  • 新発売:AppleScriptからSiriを呼び出そう!
  • iWork 12.2がリリースされた
  • 従来と異なるmacOS 13の性格?
  • 新発売:CotEditor Scripting Book with AppleScript
  • macOS 13対応アップデート:AppleScript実践的テクニック集(1)GUI Scripting
  • AS関連データの取り扱いを容易にする(はずの)privateDataTypeLib
  • macOS 13でNSNotFoundバグふたたび
  • macOS 12.5.1、11.6.8でFinderのselectionでスクリーンショット画像をopenできない問題
  • ChatGPTでchatに対する応答文を取得
  • 新発売:iWork Scripting Book with AppleScript
  • Finderの隠し命令openVirtualLocationが発見される
  • macOS 13.1アップデートでスクリプトエディタの挙動がようやくまともに
  • あのコン過去ログビューワー(暫定版)

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1390) 10.14savvy (586) 10.15savvy (434) 11.0savvy (277) 12.0savvy (185) 13.0savvy (55) CotEditor (60) Finder (47) iTunes (19) Keynote (98) NSAlert (60) NSArray (51) NSBezierPath (18) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (18) NSImage (41) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (117) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (56) Pages (37) Safari (41) Script Editor (20) WKUserContentController (21) WKUserScript (20) WKUserScriptInjectionTimeAtDocumentEnd (18) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • drive
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC