iOS12のショートカットアプリを使ってマストドン読み上げクライアントを作った
初めに
ハローワールド。
前回の記事でショートカットアプリを使ってマストドンに呟いてみました。
今回は更にショートカットアプリの可能性を感じて頂けたらと、読み上げクライアントを作ってみました。
今回はマストドンのアクセストークンを使わないのでマストドンにアカウントを持っていない方でも簡単に試して頂けます。
忙しい方のために(読む気が起きない方のために)
icloud上にショートカットを公開できたのでリンクを貼り付けておきます(中身は、この記事で作ったものに追加されている部分があります)。
一応今回作る2つのショートカットを貼り付けておきますが、上の1つだけでも大丈夫なのかもしれません(未確認)。動くかどうかも未確認です。
また まとめの方にも今回作ったショートカットで使ったアクションなどをまとめておきます。
記事内の書き方のルール
前回は書き方に統合性がなかった気がするので、今回は以下のようなルールを追加しました。
- アクション名は
[アクション名]
アクションと書きます。例えばURLアクションならURL
アクションという風にします。 - 変数名(後に出てくる)は変数
[変数名]
とします。マジック変数(後に出てくる)も同様にマジック変数[マジック変数名]
とします。例えば変数index
という風にします。 - アクションがどのコンテンツの中に入っているかを矢印を使って表します。例えば
URL
アクションはWebコンテンツの中のURLコンテンツの中にあるので、Web→URL→URL
アクションという風にします。
マストドンからタイムラインを取得
今回もWeb初心者の方でもできるだけわかりやすく説明するため、一つづつ段階的に説明していきます。
まずは、前回の記事のアクションの追加のように、Web→URL→URL
アクション、Web→URL→URLの内容を取得
アクションを追加します。
今回は次の表のような値を入力します。URLの内容を取得アクション
は前回とは違い、特に入力しなくてもいいです。
アクション名 | 項目名 | 内容 |
---|---|---|
URL | URL | [任意のマストドンインスタンスのURL]/api/v1/timelines/public |
URLの内容を取得 | 特になし | 特になし |
ちなみに社畜丼の場合は、URLの内容がhttps://mstdn-workers.com/api/v1/timelines/public
となります。
社畜丼のローカルタイムラインのAPIのURLにアクセスしてみると、json形式の文字列がバーっと現れます。ちなみにローカルタイムラインを取得する場合は上の表のURLに?local=true
という文字列を書き加えればOKです(これをクエリストリング/クエリパラメータ/クエリ文字列と呼びます)。
このjsonはリスト型です。このリスト型もショートカットアプリでは簡単に扱えます。
スクリプティング→制御フロー→それぞれで繰り返す
アクションを追加します。これは入力のリストの中の値一つ一つに対して動作を行う、Rubyのeach, JavaScriptのforEach, Pythonのforin文のようなものです。
それぞれで繰り返すアクションの中では、URLから取得してきたリストの中の値一つ一つを評価します。その中の値というのは、実は前回の記事の呟いた内容を喋らせてみようで扱ったデータと同じになります。
つまり、喋らせるだけなら前回と同じでいいというわけです。
というわけで、ぱぱっとスクリプティング→辞書→辞書の値を取得
アクションを追加して、次の表に従って項目を入力します。
項目名 | 内容 |
---|---|
取得 | 値 |
キー | content |
ここまででショートカットは次の画像の様になってると思います。
一旦実行して見ると、どうでしょう、なんとなく取得できてますよね。
htmlタグを削除
ただ、前回も言った様に、<p>タグなど邪魔なタグが現れてしまいます。削除したいですね。
ここで使えるのが正規表現。正規表現の使い方は詳しくは説明しませんが、これを使えば簡単にタグを削除することができます。
正規表現を使ってhtmlタグを削除してみましょう。
テキスト→テキスト編集→テキストを置き換える
アクションを追加してください。
そして次の表の様に入力してください。
項目名 | 内容 |
---|---|
テキストを検索 | <.*?> |
置き換え | 空欄(うっすらworldが現れている状態) |
大文字/小文字を区別 | どちらでも |
正規表現 | ON |
すると、次のようにhtmlタグが消えます。
ちょっとだけ正規表現説明
ここからはちょっとだけ使用した正規表現の解説をします。正規表現に興味がなかったり既に知ってる方は飛ばして構いません。
が、とても便利なものなので知らない人はちょっと読んでみてもいいと思います。
さて、先程のようにhtmlタグが魔法の様に消えるのは、正規表現/<.*?>/
にマッチしたものが空文字に置き換わるからです。
<>
はタグの囲み文字、そして.
が任意の一文字、*
が直前の文字の0回以上繰り返しを表します(前後の/
は、一般的に/
に囲まれたものが正規表現であることを表すものなのでつけています)。
簡単に言えば<>に囲まれているものを空文字に変換するということをやっています。
ならば/<.*>/
(上記と比べて?がない)で良いじゃないかと考えてしまいます。
ただその正規表現だと、<p>hoge</p>
という入力に対して<p>hoge</p>
すべてが正規表現にマッチしてしまいます。何故かと言うと、*はあまりにも強欲なので、マッチする値が長い方を選ぶからです。
どういう意味かというと、先程の正規表現では<p>hoge</p>
という入力に対して.*
(任意の一文字が0回以上)がp
とp>hoge</p
という2通りの値になり得ます。.*
をp
に変換すれば<p>
になり、.*
をp>hoge</p
に変換すれば<p>hoge</p>
になりますよね。
そのうち、最も長い方を選ぶので、.*
は後者を選びます。
その強欲な*
君を抑制するために?
が登場します。
.*?
というのは一般的に最短一致と呼ばれるもので、.*
が最も短いものを選ぶ様になります(通常はそう考えてもらっていいです)。
そのため、先程の例では.*
がp
を選択して、当てはまる<p>
を空文字に変換してくれるのです。
実は最短一致という名称はふさわしくない(参考ページ)のですが(僕も一度ハマったことがある)、今回は心配しなくて大丈夫です。
タイムライン読み上げ
これで怖いものはなくなりました。恐れることはありません、音声で読み上げてみましょう。
テキストを置き換える
アクションの下に、テキスト→テキストを読み上げる
アクションを追加してみましょう。
美しい声でマストドンのタイムラインが読み上げられますね。
リストを逆転させる
ただ少し待ってください。順番がおかしくないですか?
普通「古い方から新しい方」へ向かって読み上げられるべきですが、あなたの耳には間違いなく「新しい方から古い方」へ向かって読み上げられたタイムラインが入っているはずです。
これは、マストドンのタイムラインAPIの戻り値のリストが「新しい方から古い方」に並んでいるからです。
つまり、逆転させてあげれば問題がなくなるはずです。
Rubyだったらlist.reverse
で事足りるのですが、ショートカットには逆転してくれる便利なアクションはありません。
が、しかし、無いならば作れば良いのです。
実は、ショートカットには「入力」と「出力」があります。
例えばURLの内容を取得
アクションの入力はURL、出力はそのURLの内容でした。
同様に自分で作ったショートカットにも同様に入力と出力を作ることができます。
つまり「リストを逆転する」ショートカットを作れば良いのです。さながらプログラミングの関数ですね。
リストを逆転するアルゴリズム
今回のショートカットはちょっと長いので、まずリストを逆転するアルゴリズムをまとめてみました。
今後どういったことを行うかが想像しやすくなると思います。
今回のアルゴリズムはショートカットアプリ用になっています。
-
ショートカットの入力
変数をリスト化し、項目数を数える - 1.でカウントした項目数を変数
index
に設定する -
1.でカウントした項目数回以下を行う
- ショートカットの入力をリスト化したものの変数
index
番目の項目を変数retVal
の先頭に追加する - 変数
index
の値から1を引き、変数index
に再代入する
- ショートカットの入力をリスト化したものの変数
変数
retVal
をショートカットの戻り値とする
ちなみにRubyのコードにするならこうでしょうね。かなり正確に再現しました。
def reverse(ショートカットの入力)
リスト = Array(ショートカットの入力)
数 = リスト.length
index = 数
retVal = [] # ショートカットではここが不要
数.times do
retVal.append(リスト[index - 1]) # ショートカットではここの-1が不要
index -= 1
end
end
1.ショートカットの入力をリスト化し、項目数を数える
まずは、新しくショートカットを作って、わかりやすいように「リバース」とでも名前をつけてください。
そしてまずはアルゴリズムの1.を実装します。と言ってもここは難しくありません。
まずはスクリプティング→リスト→リスト
アクションを追加してください。
そして、すでにある1件, 2件を一旦削除して、新規項目を追加してください。
テキストのところをタップしてみるとキーボードが開きますが、その上に変数と書かれたバーがあります。
そこに変数ショートカットの入力
がありますので、それをタップしてください。
これで、ショートカットの入力をリスト化できました。
変数を取得
アクションはあるのに、変数ショートカットの入力
が取得できないみたいです(もっとスマートな方法を見つけたら教えてください)。
次にリストの項目数を数えるのですが、これはスクリプティング→コンテンツ→カウント
アクションで容易に実装できます。
カウント
アクションを追加し、カウント項目を項目にすればこれでもう項目数は取得できました。
2. 1.でカウントした項目数を変数index
に設定する
これはただ変数に突っ込むだけです。
スクリプティング→変数→変数を設定
アクションを追加し、変数名をindex
(または任意の名前)にしてください。これで2.は完了です。
3.1.でカウントした項目数回以下を行う
これはつまり、繰り返しです。項目回数繰り返せば良いのです。
スクリプティング→制御フロー→繰り返す
アクションを追加してください。
ここで項目数回繰り返したいのですが、どうしたら良いでしょう。
繰り返しの部分をタップすると次のような選択肢が現れます。
これで変数を選択できるようになります。
ここで、マジック変数を選択をタップしてください。
すると、アクションとアクションの間の先に、例えばリスト
や数
といった表示が増えましたよね。
これは、アクションの出力値を変数として扱うことが出来る機能です(と思っています)。
ここで、マジック変数数
を選択してください。
これで項目数回繰り返せます。
3-1.ショートカットの入力をリスト化したものの変数index
番目の項目を変数retVal
の先頭に追加する
噛み砕いて言えば、入力の変数index
番目を戻り値のリストに追加するですね。
ショートカットアプリでは通常のプログラミング言語とは違い、リストのインデックスが1から始まります。仮に項目数が20個とするなら、インデックスは0〜19ではなく1〜20となります。
そのため、先程項目数をそのままindexに入れたので、最初は一番後ろの値を出力するリストの最初の項目になるということです。
リスト変数に追加する方法ですが、スクリプティング→変数→変数に追加
アクションで簡単に再現できます。
このアクションは変数があれば、その値の最後尾に入力を追加、なければ新しく変数を作るというものです。
まずは ショートカットの入力をリスト化したもの を取ってきます。
スクリプティング→変数→変数を取得
アクションを追加します。
変数を選択するところで、マジック変数を選択し、マジック変数リスト
を選択してください。
次にindex番目の項目をリストから取得するため、スクリプティング→リスト→リストから項目を取得
アクションを使ってindex番目のリストを取得します。
取得を項目のインデックス、インデックスを変数index
してください。
最後に変数に追加
アクションで変数名をretValにしましょう。
3-2. 変数index
の値から1を引き、変数index
に再代入する
すなわち、Rubyで言うなら
index -= 1
ですね。
スクリプティング→変数→変数を取得
アクションで変数index
を取得し、スクリプティング→計算計算
で-1を行い、スクリプティング→変数→変数を設定
アクションで変数index
に再代入すればいいだけです。
つまり、画像のようになります。
4.変数retVal
をショートカットの戻り値とする
ショートカットの戻り値はショートカットの最も下の出力であると考えられるため、一番下に変数を取得
アクションで変数retVal
の値を出力してあげましょう。
テスト
長々と説明したこのリバースショートカットも、完成したはずなので、一旦こんなショートカットを作って試してみましょう。
ショートカットを実行
アクションはスクリプティング→Shortcutsにあります。
これを再生してみると、下の方に4と表示されると思います。左にスワイプすると3, 2件, 1件と続々表示されます。
反転されてますね!
タイムラインを反転させる
リバースショートカットを作った我々は無敵なので、ただただ、URLの内容を取得
アクションとそれぞれで繰り返す
アクションの中間にショートカットを実行
アクションを追加して、リバースショートカットを呼んであげましょう。
まとめ
長々と説明してきましたが、これでタイムラインが読み上げられました。
ただ少し待ってほしい、読み上げただけじゃないか。
これでは最初に取得した20件のtootが読まれるだけで、終わったら毎回毎回タップしなきゃいけないじゃないか。
というあなたのために、完全版がこちらに上がっています。
これは社畜丼のローカルタイムラインの読み上げショートカットで、実行中は無限に読み上げ、一度読み上げたものはもう一度読み上げない、といった工夫がなされてます。
と言っても4, 5アクション程度を追加しただけなんですけど。
今回のアクションを次の表にまとめました。
読み上げショートカットの表
アクション名 | 項目名 | 内容 |
---|---|---|
URL | URL | [任意のマストドンインスタンス]/api/v1/timelines/public |
URLの内容を取得 | なし | なし |
ショートカットを実行 | ショートカット | リバース |
それぞれで繰り返す | なし | なし |
辞書の値を取得 | 値 | content |
テキストを置き換える | 検索 | <.*?> |
置き換え | (何も入力しない) | |
正規表現 | ON | |
テキストを読み上げる | なし | なし |
繰り返しの終了 | なし | なし |
リバースショートカットの表
アクション名 | 項目名 | 内容 |
---|---|---|
リスト | テキスト | ショートカットの入力 |
カウント | カウント | 項目 |
変数を設定 | 変数 | 変数index
|
繰り返す | 繰り返し | マジック変数数
|
変数を取得 | 変数 | マジック変数リスト
|
リストから項目を取得 | 取得 | 項目のインデックス |
インデックス | 変数index
|
|
変数に追加 | 変数 | 変数retVal
|
変数を取得 | 変数 | index |
計算 | 処理 | - |
オペランド | 1 | |
変数を設定 | 変数 | index |
繰り返しの終了 | なし | なし |
変数を取得 | 変数 | retVal |
再三になりますが、ぜひショートカットの可能性を感じて色々やってみてください。
以上です。
Author And Source
この問題について(iOS12のショートカットアプリを使ってマストドン読み上げクライアントを作った), 我々は、より多くの情報をここで見つけました https://qiita.com/sa2taka/items/559032a89e65fd4bfcb0著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .