Googleマップのルート検索結果をカレンダーに追加するサービスメニュー

iOS 版の Google Maps アプリは電車やバスを使う場合のルート検索結果の詳細表示画面で、再下方にスクロールすると「カレンダーに追加」ボタンがありカレンダーアプリに予定を追加することができますが、MacOS のブラウザを使った場合に同じことができないものかと模索した結果、Automator でサービスメニューに追加するべくワークフローを作成することにしました。ファイルは Dropbox に置いたのでご自由にお使いください。

GMapルート検索結果をカレンダーに追加.workflow

使い方は、

  1. ダウンロード後、ZIP 解凍してダブルクリックをするとサービスインストーラーのダイアログが表示されるのでインストールボタンを押してください。
  2. ルート検索の詳細を表示した画面で、サービス>GMapルート検索結果をカレンダーに追加をメニューから選択してください。現在、Safari と Chrome のみ対応しています。

    電車/バスルート検索の詳細画面以外でサービスを実行するとエラーを返します。

  3. カレンダーアプリが前面に来て一覧を表示するので、予定を入れるカレンダー名を選択して OK を押してください。
  4. 予定の内容は、可能な限り iOS 版に近いものにしました。日跨ぎの予定に対応し、出発/到着時間の指定により一週間内で日付を判定して追加するようにしました。

出発/到着時間の設定にカレンダーで選択ができるにも関わらずその指定日へ予定が追加できないのは、グーグルが電車やバスの運行状況を曜日毎でのみデータを保持しているからなのか、検索結果に曜日しか表示されないという理由があります。AppleScript のソースコードは最初の手順で Automator で開くと見ることができるので、改変などご自由にどうぞ。

技術的な余談で言うと、Yosemite から利用できる JavaScript for Automation (JXA) での記述も検討したのですが、2つのブラウザの処理の違いとコード量、結局 JavaScript で DOM 操作をすることなどを考えると従来の方法になってしまいました。

参考:

AppleScriptでHTML解析

いよいよスプラトゥーン2の発売が迫り子供のお強請りが正に言葉通り凄まじくなって来たので、と言うのが今回の要件です。

実際にはこの初版運用から4回の販売があり、初めの3回は iPhone のメール通知の発見に遅れたためプッシュ通知が確実なメッセージアプリの利用に変更しました。4回目は通知が来たものの5分間隔では時既に遅しと言うことで、巡回の間隔を短くしました。

解析というほど大袈裟ではなく単に変更を確認するのは “SOLD OUT” ボタンタグの有無にし、混雑時のエラーページを回避する条件分岐を加えたそんなこんなで現在この様なコードで常駐しています。

property INTVAL_CHECK : 90
property INTVAL_NOTIFY : 300
property INTVAL : INTVAL_CHECK
property BASE_URL : "https://store.nintendo.co.jp/customize.html"
on idle
 try
  set rawHTML to do shell script "curl -si " & BASE_URL
  if paragraph 1 of rawHTML is "HTTP/1.1 200 OK" and rawHTML contains "カートに進む" then
   set INTVAL to INTVAL_NOTIFY
   my sendMessage("+8180********", "マイニンテンドーストアで Nintendo Switch の販売が開始されました。" & " " & BASE_URL)
   else
    set INTVAL to INTVAL_CHECK
  end if
 end try
 return INTVAL_CHECK
end idle
on sendMessage(targetBuddyPhone, targetMessage)
 tell application "Messages"
  set targetService to 1st service whose service type = iMessage
  set targetBuddy to buddy targetBuddyPhone of targetService
  send targetMessage to targetBuddy
 end tell
end sendMessage

当初 curl コマンドをオプション指定無しに利用していたところ、プログレスメータをアラートダイアログに表示するということがあり s オプションを、更に鯖落ちしていた場合に備え i オプションを付与しレスポンスヘッダが 200 の場合にのみ処理を実行する様にしました。また、メッセージアプリの宛先がメールアドレスにした場合のエラーを解決できなかったので仕方なく電話番号にしました。

自分からメッセージが送られるという特殊性を活かし、iOS のアドレス帳編集からメッセージ着信音を特別分かりやすいものにすると認知向上に尚良いかと思います。(因みにバルーンファイトのゲームオーバー音を設定しました)

最後に開発環境上で動作させることを考慮し Info.plist に <key>LSBackgroundOnly</key><true/> を追加することでドックにもアプリ切替時にもアイコンを表示させない様にしました。後は増産を待つばかり。

追記:
「0以外の状況でコマンドが終了しました。」というエラー内容(英語では “The command exited with a non-zero status”)は、シェルスクリプトの実行が失敗した際に 0 以外の数字を返した場合に発生することとその回避方法をアップルの公式文書で知りました。

http://hkitago.tumblr.com/post/162968916786

man curl を参照すると 1 から 99 までと XX を返す様で、シェルスクリプトのリダイレクトを利用すると空の値を返した際に次の行にある分岐条件が増えることが格好良く思わなかったので今回は Try ハンドラを利用しました。余談で公式文書にツッコミを入れると、リダイレクトを利用する場合は文末にアンパサンドが必要でないか、と…

追記1:
販売が開始されたら通知の間隔を大きくする目的で、2つの巡回用の数値変数を与えて条件分岐で変更できる様にしました。最初の通知を見逃すと痛手なのですが、気づいて買い物手続き中に通知だらけになるのも避けたいという難しいところ、リマインダアプリの「実行済み」ボタンの様な機能を通知持たせることができれば最善だと感じる苦肉の策。

追記2:
「文字列 “SOLD OUT” を含まない」と言う条件だとコード内でコメントアウトされていたり CSS で非表示になっていた場合に失敗することが分かったので修正。

参考:

Safari 9.1.1でAppleScriptからJavaScriptを実行する

以前、Ingress のプレイ記録用途に AppleScript を書いたのだけど、半径3キロメートルに及ぶノバ作戦を近所で開催した時にもっと大きなインテルマップを表示しようと、次のようなコードを追加していました。

on fullScreenIntelMap()
	tell application "/Applications/Safari.app"
		tell document 1
			do JavaScript "document.getElementById('dashboard_container').style.left='0';document.getElementById('dashboard_container').style.top='0';document.getElementById('dashboard_container').style.right='0';document.getElementById('dashboard_container').style.bottom='0';document.getElementById('comm').style.display='none';document.getElementById('player_stats').style.display='none';document.getElementById('rs_box').style.display='none';"
		end tell
	end tell
end fullScreenIntelMap

この関数を起動時の on run と再読み込み時の on idle で実行すると、ヘッダ部分やフッタ部分を隠しブラウザのフルスクリーンモードにして可能な限り広域な地図状況を記録しておくことができるのですが、最近になってこのスクリプトを使うと Safari が次のようなエラーを返してきました。
スクリーンショット 2016-06-01 9.03.48

You must enable the ‘Allow JavaScript from Apple Events’ option in Safari’s Develop menu to use ‘do JavaScript’.

この内容に従って「開発」メニューを覗いてみると次のように「Apple Events からの JavaScript を許可」というコマンドがありました。

スクリーンショット 2016-06-01 9.04.24
この見慣れぬコマンドについて確認しようと Apple のサポートページを見ると未だ記述がないので、どうやら最新のバージョン 9.1.1 から追加されたものと思われます。そこでもう少しおググりなさってみると、数日前に “do JavaScript 記述のある AppleScript が動かなくなったよ〜” という内容で、とあるマックサイトのフォーラムに投稿している人がいました。

その内容によると、どうやら Safari の「開発」メニューを表示しておかないと上述したようなエラー内容を表示せず、コンソールに不可解なエラーメッセージだけが残るそうなので注意が必要です。

http://hkitago.tumblr.com/post/145244516611

確かに近年 JavaScript の台頭と安全性について語られることが増えていますが、わざわざ開発メニューから設定する必要があるのは柔軟性という点で開発者にとってはなかなか厳しい変更点なのではないかと思いました。またこのフォーラムでも懸念されていますが、Safari 以外で AppleScript と連携ができる(特にウェブ開発で使うような)アプリケーションの対応についても今後の動向に少し注目しておく必要がありそうです。

参考:

定期的に再読みしてスクショを撮るAppleScript

少し暑くなってきて朝方のイングレス活動(通称イン活)が気持ち良くなってきたのですが、イン活用に使い始めたグーグルプラスを眺めていると、コントロールフィールド構築の時間経過をアニメーション GIF にして投稿している人がいて、帰宅後に慌ててインテルマップのスクリーンショットを撮るよりは効果的だろうと思い、その方法を考えました。

まず参考にした Reddit のコメントから、ブラウザのエクステンションと言われる機能拡張で定期的な再読み込みをしながら、i=1;while [1];do screencapture ~/Desktop/$i.png;let i++;sleep 30;done のようなシェルスクリプトを実行させる方法を試してみたのですが、省エネルギー設定の画面スリープにより期待通りに撮影できていなかったり、最後にプロセスをプロンプトから終了するのが面倒だったので、これらの問題をまとめて AppleScript のアプリケーションにしたコードがこちらになります。

property NOW : 0
property INTVAL_CAP : 55
property INTVAL_RELOAD : 3300
property FILENUM : 0
property thePath : ""
property thePID : ""
on run
	set thePath to (choose folder name with prompt "Where would you like to save your file?")
	do shell script "caffeinate -di &>/dev/null &"
	set thePID to (do shell script "ps ax | grep caffeinate | grep -v grep | awk '{print $1}'")
end run
on idle
	set FILENUM to FILENUM + 1
	do shell script "screencapture -mx -T1 " & quoted form of (POSIX path of thePath & FILENUM & ".png")
	if NOW mod INTVAL_RELOAD = 0 and NOW is not 0 then
		tell application "/Applications/Google Chrome.app"
			reload active tab of window 1
		end tell
	end if
	set NOW to NOW + INTVAL_CAP
	return INTVAL_CAP
end idle
on quit
	if thePID is not "" then do shell script ("kill -9 " & thePID)
	continue quit
end quit

インテルマップの表示には Google Chrome ブラウザを使い、撮影箇所を全画面で表示してから右上の Link アイコンを押して恒久リンクをアドレスバーにコピペして再度読み込んでおきます(この辺りも自動化したいところ)。その後、このアプリケーションを起動すると画像の保存先を尋ねられるので適当にデスクトップにフォルダを作るなりしてインテルマップを表示しておくと5分毎に再読み込みし、30秒毎にスクリーンショットを撮影し連番を付けた PNG 画像を先に指定したフォルダへ保存していきます。

帰宅後はこのアプリケーションを終了すると省エネルギー設定も元通りになります。省エネルギー設定を無効にする caffeinate コマンドは Mountain Lion 以降となりますので、このアプリケーションの動作条件もこれに沿うことになります。また、出かける前には画面の光度を低くして行くといいかもしれません。

連番の PNG ファイルから動きの無いものは削除し(ここが手作業なのは少し厄介笑)プレビューアプリを使ってアニメーション GIF にするとこうなります。

最後に、このスクリプトを Automator で使うにはイベントハンドラを一度だけ実行し終了してしまうので上手くいきません。ですので、スクリプトエディタにコピペして保存する際には、次のようにフォーマットを「アプリケーション」とし「ハンドラの実行後に終了しない」オプションを有効にしてください。更に、再読み込みの時間が短すぎるとアカウント停止になる可能性もあるのでご注意ください。

スクリーンショット 2015-05-13 12.28.45

近年流行りのクラウドソーシングでも定期的に画面のスクショを撮る時給計算アプリを起動して作業する必要があったり、何かと応用ができそうな気もします。アニメーション GIF の作成手順については次の投稿にしたいと思います。

更新(5/22):
先の公開時のリロード時間で数回試したところ、特にプレイ時間が1時間を超えるような場合に次のような “Oops! Something went wrong..” というエラーが表示され復旧まで半日を要することが起きました。コードを読むと60分で “Human presence not detected.” を表示し、1分で再描画しているようでしたので、再読みとスクリーン撮影の時間間隔の設定を長くするように変更しました。
スクリーンショット 2015-05-20 14.23.55

同一IPで且つ、等間隔の再読み込みでボット判定されていそうなので、INTVAL_RELOAD を3000〜3300くらいの間で乱数にすることも検討する必要がありそうです。

数回このエラーを経験した後に下記にリンクしたヘルプページを参照し、右上にある「お問い合わせ」から問題の内容を送信すると「公式のツール以外使うなよ、コノヤロー!」という趣旨の自動送信メールが返ってきて復旧しました。どうぞお気をつけください。

参考:

Parallelsアプリと衝突するAppleScript構文

以前「ChromeからSafariで開くサービスメニュー」というものを作ったのですが、ごく最近になって次のようなダイアログと共に「アクション”AppleScript を実行”でエラーが起きました。」という内容で実行に失敗したと返すようになっていたことに気がつきました。

スクリーンショット 2015-03-16 9.26.26

そこで「ワークフローを表示」ボタンを押し、AppleScript の部分だけをスクリプトエディタ.app で作成した新規文書へコピペし保存してみたところ「end of line があるべきところですが property が見つかりました。」という内容のエラーを、スクリプトの tab をハイライトしつつ返してくることが分かりました。

スクリーンショット 2015-03-16 9.22.37

このエラーの内容と関連する Google Chrome アプリケーションをキーワードの材料におググりなさってみたところ、下記参考にあるリンクが目に止まり、問題は Parallels Desktop for Mac がインストールされている場合に、AppleScript で tell application "Google Chrome" のように記述すると、Google Chrome に限らずエミュレータ内に同名のアプリケーションがあった場合に衝突し処理に失敗するいうことでした。

ということで、Parallels Desktop がインストールされている条件下では、アプリケーションを呼び出す場合に絶対パスを使うか、プロセスIDを使うかのどちらかで処理する必要があり、具体的にはこのような書き方になります。

  • tell application "/Applications/Google Chrome.app" -- fully-qualified path name
  • tell application id "com.google.Chrome" -- process id

最後に実はもう一つ方法があって、それは Parallels をアンインストールし 他のエミュレータに移行するといいそうです。笑

これは一見突拍子もない発想に思えたのですが、ファイルを右(副)クリックした際に表示されるコンテキストメニューの「このアプリケーションで開く」コマンドを使う時にアプリケーション名の一覧が現れることで分かるように、Parallels の仮想環境を意識させないシームレスな手法が仇となった形ですので、ひょっとしたらこの機能を停止することで従来の書き方のままで良いのではないかと思ったところ、見事に当たりました。

スクリーンショット 2015-03-16 9.50.20

仮想環境を起動した際のウィンドウ右下にある歯車アイコンを押すと環境設定が表示されるので「オプション>アプリケーション」と進み「Windows アプリケーションを Mac と共有する」チェックボックスをオフにすることで tell application "Google Chrome" という従来の簡素な記述が可能になります。

結論としては、この機能を使わないのであればコンテキストメニューの表示が軽くなることもあるので、私的に利用する AppleScirpt プログラムの場合に限りオフにしてしまって記述はそのままという方が良いかもしれません。

参考:

Safariのリーダーを自動的に表示

JavaScript の安定性が今のところ高い Chrome ブラウザでウェブアプリによるサービスを使っていて、例えば Feedly の場合は長い読み物の記事なんかを Safari のリーダー機能を使って読みたくなるという前回の話の続きで、Chrome で表示中の URL を Safari に渡すサービスを作ったまでは良くても、Safari のリーダーを自動的に表示したくなるのが怠け癖の性ということからちょっと改変。

--
-- open currently active Chrome tab with Safari
-- forked from https://gist.github.com/3151932 and https://gist.github.com/3153606
--
property theURL : ""
 
tell application "Google Chrome"
	set theURL to URL of active tab of window 0
end tell
 
if appIsRunning("Safari") then
	tell application "Safari"
		tell front window
			open location theURL
		end tell
	end tell
else
	tell application "Safari"
		do shell script "open -a "Safari"" -- Safari not running, so start it
		tell front window
			open location theURL
		end tell
	end tell
end if
 
tell application "Finder" to activate -- Chrome is fullscreen, call Finder once to activate Safari menu
delay 2
tell application "Safari" to activate
tell application "System Events" to keystroke "R" using command down
 
on appIsRunning(appName)
	tell application "System Events" to (name of processes) contains appName
end appIsRunning

Safari の起動と終了の判定はそのまま利用しつつ、一旦 Finder を前面に持ってきているのは2つの理由があって、Chrome がフルスクリーンの場合は Safari が前面にくるにも関わらずウィンドウが有効化せず「リーダーを表示」メニューも無効になって選択ができなくなってしまう(ミッションコントロールの?)問題の回避と、背面で読み込みを行なった方が Safari の処理が早くて delay が小さくて済むということからです。

スクリーンショット 2013-08-16 10.20.19

加えて Safari が終了していて且つ多くのタブを復元する必要がある時や背面で動画を書き出しているような大きな処理が CPU 使用率を占有しているような場合は delay を大きくする必要もあり、この部分は決してスマートとは言えないので良い方法があれば教えてください。Reeder for Mac の登場まで今のところ上手く処理出来ているのでこれで良し、と…。

参考:

Googleマップに表示する連絡先プラグインを更新

SNS との連携が可能になった連絡先.app (旧:アドレスブック)で、いつまでたっても Apple が対応しない「この住所の地図を表示」機能を補完するためのプラグインを更新しました。次のリンクからダウンロードしてディスクイメージを展開後に ab2maps.google.co.jp.scpt を、その右横のエイリアスになっている Address Book Plug-Ins フォルダにドロップしてお使いください。

Google Maps Plugin for 連絡先(ab2maps.google.co.jp)

そして更新点は次の2点です。

  • 日本語版(maps.google.co.jp)を読むようにしました。
  • メニューラベルの表示名称を変更しました。

使い方は、住所欄の先頭左横にある「自宅」や「勤務先」ラベルをクリックすると表示される「Google マップ上に表示」を選んでください。(国際化の名残で国欄に「日本」「japan」もしくは「jp」の記載がないと表示されません)

スクリーンショット 2013-08-09 6.29.00

いずれにしても知り合い程度の繋がりの人たちにストリートビューで自宅を見られたくない方は公開範囲の設定を見直しましょう。

iOS を発端とした地図問題に注目がありますが、OS X 10.9 Mavericks ではどうなるのか楽しみでもあります。

参考:Google Maps Plugin for アドレスブック

ChromeからSafariで開くサービスメニュー

Google リーダーの終了に伴って Feedly へ移行することにしたのだけど、元々このサービスは Google Chrome の機能拡張を主に構築されていたことや、OS X のアップグレードを前に Safari が大分もっさりしていることなどから、開発用途でもあるデフォルトブラウザを Safari にしつつもニュースリーダーとして Google Chrome を使う事にした。ところがページロールがあり広告だらけな長めの読み物を見る時にはどうしても Safari のリーダー機能を使いたくなる時があって、いちいちアドレスバーの文字列をコピペして移動するのは面倒なので表題のものを Automator で作る事にした。

作るのは至って簡単な数分の作業です。

  1. Automator を起動し、ファイル>新規>サービス というメニューコマンドをクリックしたら選択ボタンを押します。
  2. “サービス”は、次の項目を受け取ります:入力なし/検索対象:Google Chrome.app とします。
  3. 左側のパネルにある “AppleScript を実行” というアクションを右側のパネルにドロップし gist:5575774 をコピペします。
  4. “Safariで開く”というような適当な名前を付けて保存します。(保存先と拡張子は Automator にお任せ)

そうすると、Google Chrome を前面に持ってきた際に「Chrome>サービス>Safariで開く」というメニューコマンドが確認できるようになります。(本来は副クリックでも表示できれば良いのですが、Google Chrome がその機能を書き換えてしまっているのでちょっと不便ですねえ。)

加えて参考リンクにも解説されているように、各サービスには独自のショートカットキーを割り当てられるので「>システム環境設定>キーボード>サービス」と進み、スクロール下方の一般カテゴリに先ほど作成したサービス名が見えると思うので他と衝突しないキーの組み合わせを割り当てます。例では「コマンド+シフト+O」としていますが、ドックにウィンドウが入ってた場合に隠し機能でもあるゆっくりとしたアニメーション効果がイラッとする場合があるのでシフトキーを使わないようにすると良いかと思います。(このスローアニメーションをオフにする方法は現在無いようで…)

スクリーンショット 2013-06-29 4.39.44

そうしてる内にもこんな知らせを受けて、ジェスチャーにもキーにも対応している Reeder へ戻る羽目になりそうな予感です。

参考:

選択部分から新規メモを作成サービスメニュー for Mountain Lion

以前作成していた「選択部分から新規メモを作成サービスメニュー」が Mountain Lion になってから Notes(日本名「メモ」)アプリの登場と、ダウンロードしたアプリケーションの実行を許可する「セキュリティとプライバシー」環境設定という2つの仕様変更から問題があったので更新しました。

ダウンロード:選択部分から新規メモを作成.workflow

OS X 10.8 上のインストール手順:

  1. ZIPファイルをクリックして解凍
  2. コントロールキーを押しながら解凍後にできたワークフローファイルをクリック
  3. ダイアログに従ってインストールボタンをクリック

最後にインストールを初期状態の環境設定で検証していて分かったのは、まず次のような警告が立ち上がったので、

「環境設定>セキュリティとプライバシー>一般>アプリケーションの実行許可」のラジオボタンを「すべてのアプリケーションを許可」に選択したところ次のような警告で教えて頂いた次第。(結局ラジオボタンは元に戻した)

使い方で前版と異なる点は、アカウントを途中で選択する必要があることと作成したメモの件名が「新規メモ」となってしまうことで、前者はデフォルトアカウントを取得するプロパティが現時点で与えられていないことと、後者は件名を入力するダイアログを出しても良いのだけどその後編集して一行目が件名に割り当てられることを考えて敢えて機能を無視したという経緯です。

これでまたレシピサイトなどからメモをガンガン構築できるようになりました。楽しいメモライフを!

参考: