思索的逍遥の記。

いろいろな考え事。

Pythonista 3 で Google 翻訳を使いやすく (3) iOS ショートカットアプリとの連携

前回から随分間が空いてしまった。前回でおおよそ主要機能は完成していた(全てのコードは前々回の記事に記載)。

sutukeisu.hatenablog.com

sutukeisu.hatenablog.com

今回は Pythonista 3 と iOS のショートカットアプリの連携、そしてアラート表示について触れていきたい。しばらく放っておいてしまったこのシリーズもこの記事で完結となる。

---- 追記:2020/04/18 ----

iOS 13では不具合によりこの記事の方法でスクリプトに引数を渡すことはできない。URLスキームを用いた方法でこの記事の目的を実現できるので、新しくその方法についての記事を書いた。現在はそちらを参照されたい。

sutukeisu.hatenablog.com

また、この不具合への対処方法がなかった時期に、ショートカットアプリを経由せずにPythonistaのappexモジュールとGoogle Apps Scriptを使って翻訳結果を取得するスクリプトも作成した。そちらの記事もある。

sutukeisu.hatenablog.com

---- 追記終わり ----

なぜ "Run Pythonista Script" を使わないのか

Pythonista の使い方をご存知の方は、iOS の共有シートから "Run Pythonista Script" のボタンを介して起動すれば良いのではと思われるかもしれない。

f:id:sutukeisu:20190907210654j:plain:w250

実際、最初はそうしたかった。アプリ内の "URL to QR Code" 等の Example を参考にすれば、Web ブラウザからの URL の取得も容易なことがお分かりいただけると思う。

しかし、問題が1つあった。それは、共有シートから Pythonista を起動するとき、通常のアプリ起動よりもメモリの割り当てが少ないことである。WebView を同時に2つ保持している拙作のスクリプトは、このメモリ制限を超えてしまうらしく、起動してもすぐに落ちてしまった。

そこで、App Extension としてではなく Pythonista を直接起動するという方法を取らなければならない。このときこれを簡単に実現する手段として、Apple 公式のショートカットアプリを利用する方法を今回は採用した。

ショートカット

ショートカット

  • Apple
  • 仕事効率化
  • 無料

ショートカットを作成する

まずはショートカットアプリを開き、ライブラリ画面の「ショートカットを作成」を選択する。ショートカットの編集画面が開くので、検索欄に「テキスト」と打ち込むと、テキストの処理に関連するアクションがたくさんヒットする。この中で、単に「テキスト」と書いてあるアクションを選択する。

f:id:sutukeisu:20190907214107j:plain:w250

このアクションには「テキストを入力...」という欄がある。ここには「ショートカットの入力」を入れる(キーボードの予測変換領域に表示されている)。これにより、このショートカットの呼び出し元から入力を取ることができる。

次に、検索欄に「Pythonista」と打ち込む。Pythonista 関係のアクションは「スクリプトを編集」と「スクリプトを実行」の2つある。今回は後者を使う。

ここで、説明文を読む(なぜか親切にも日本語。なぜアプリ自体とドキュメントは英語だけなのか……)。すると、どうやらスクリプトに変数を渡すことができ、スクリプト側ではそれをsys.argvで受け取れるという。とても馴染みのあるアクセスの仕方ができる。

f:id:sutukeisu:20190907214307p:plain:w250 f:id:sutukeisu:20190907214353j:plain:w250

スクリプトを実行」アクションには「スクリプト」の欄がある。ここには、スクリプトのパスを、Pythonista のルートディレクトリからの相対パスで入力すれば良い。拡張子は必要ない(筆者の場合は "MyTools/TranslateSet/translate_set" と入力している)。

使うアクションはこの2つ全てである。あとは右上の設定アイコン(スイッチのオンオフが交互になっているマーク)を押して、好きな名前とアイコンを決める。そして今回の場合、「共有シートに表示」をオンにする。すると「受け入れの種類」という項目が新しく生えるので、これを開く。デフォルトではどんな種類の入力も扱えるようになっているが、今回は URL のみを扱うだけなので、チェックは URL のみに入れる。

これで、ショートカットアプリ側での設定は終了である。ショートカットの内容が下の画像のようになっていれば良い(URL のみを受け入れる設定にしたので、「このショートカットはURLを受け入れます」と表示されている)。

f:id:sutukeisu:20190907220717p:plain:w250

あとはスクリプト側で、受け取った URL を使う。

アラートの表示

前回の最後のスクリプトに手を加える。

Pytonista の console モジュールに alert 関数がある。以下の画像のように選択肢を表示できる。

f:id:sutukeisu:20190907221738p:plain:w250

公式ドキュメントによると、引数は以下のようになっている。

console.alert(title[, message, button1, button2, button3, hide_cancel_button=False])

なので、タイトル、説明文、最大3つまでのボタンのテキストを引数として渡せば良い。戻り値は、button1が選択されれば1button2が選択されれば2button3が選択されれば3である。Cancelボタンを押したときは戻り値が返らず、KeyboardInterrupt となってスクリプトが終了する。

今回のコード

sys.argvは通常通り、第1要素はスクリプトのファイル名で、第2要素以降が引数である。Pythonista で直接実行したか、ショートカット経由で起動して引数に URL を持っているかで条件分岐している。そして、受け取った URL のサイトを表示するか、あらかじめようしてある選択肢(Google のトップページか、Pythonista のドキュメント)を表示するかで、ui.WebView.load_url()に渡す URL を変更している。自分で使うことだけを念頭に書いたので、かなり付け焼き刃なコードになってしまっているのは申し訳ない。

import ui
# 以下の2つの import を加える
import console
import sys

# ...
# 中略
# ...

webview1 = v['webview1']
webview1.delegate = MyWebViewDelegate()

# ここから前回のコードとの差し替え
# 元のコードは以下の通り:
# webview1.load_url('http://omz-software.com/pythonista/docs/')
# textfield.text = 'http://omz-software.com/pythonista/docs/'
text = ''
if len(sys.argv) > 1:
    text = sys.argv[1]
if text.startswith('http://') or text.startswith('https://'):
    result = console.alert('URLを開く', '取得済みのURLがあります。開きますか?', 'はい', 'Googleを開く', 'Pythonista Docs を開く')
    if result == 2:
        webview1.load_url('https://www.google.co.jp/')
        textfield.text = 'https://www.google.co.jp/'
    elif result == 3:
        webview1.load_url('http://omz-software.com/pythonista/docs/')
        textfield.text = 'http://omz-software.com/pythonista/docs/'
    else:
        webview1.load_url(text)
        textfield.text = text
else:
    result = console.alert('URLを選択', 'どちらを開きますか?', 'Googleを開く', 'Pythonista Docs を開く')
    if result == 1:
        webview1.load_url('https://www.google.co.jp/')
        textfield.text = 'https://www.google.co.jp/'
    else:
        webview1.load_url('http://omz-software.com/pythonista/docs/')
        textfield.text = 'http://omz-software.com/pythonista/docs/'
# 差し替えはここまで

webview2 = v['webview2']
webview2.load_url('https://translate.google.co.jp/?hl=ja&tab=wT')
webview2.alpha = 0.0

webview1.bring_to_front()

v.present('sheet')

これで全ての作業は終了である。第1回の記事に掲載した GIF 画像のような流れがこれで実現する。

終わりに

本当はもっと早くこの記事のシリーズを終わらせる予定だったが、体調がままならなかったりして遅れに遅れてしまった。終わらせることができてよかった。

今でも Pythonista を生活に役立てる試みを続けている。暗記カードもどきのようなものを作って英単語の暗記に使ったり、numpy や matplotlib がデフォルトで入っていることをいいことに、統計の計算に使ったりしている。いつでもどこでも気軽に使用できるスマートフォンという環境でプログラミングを行えるということは素晴らしい。Pythonista は流石に重量級の用途には向いていないが、ちょっとした短いスクリプトでも十分役に立つと感じられる。

これからもちょっとずつ、楽しく役に立つコードを考えていきたいと思う。