はてなブログを更新したら Mastodon に投稿する IFTTT を作る → mstdn.jp 対策に GAS も併用
はてなブログに限らずだが、RSS フィードを発行するブログ等の媒体を更新した時に、その RSS フィードの更新を検知して IFTTT の Webhook が発火し、Mastodon API を使ってブログの更新内容をトゥートする、そんな仕組みを作ってみた。
前半は通常のマストドン・インスタンスで成功するであろう構成で、後半は mstdn.jp
固有の問題を解消するための対策版を紹介する。
目次
- 準備するモノ
- Mastodon API の準備をする
- IFTTT の Applet を作成する
mstdn.jp
は IFTTT からのリクエストを拒否している模様- GAS を経由して送信する
- 参考文献
準備するモノ
- Mastodon のアカウント : 以降の例では
mstdn.jp
のテイで記載している →mstdn.jp
は IFTTT 連携不可能 (後述) - IFTTT のアカウント
- トゥートしたい RSS フィードの URL : はてなブログの場合、
https://【ブログ URL】/rss
に該当する mstdn.jp
の場合のみ : Google Apps Script を作成するための環境 (Gmail アカウントを持っておけば良い)
Mastodon API の準備をする
何やら Mastodon の管理画面に「アプリ」という画面があり、ココで作ったアプリでも Access Token とかが発行できたのだけど、コレとは違うやり方で Access Token を発行しようと思う。多分結果は同じだと思う。
まず、次のようなパラメータを組み立てて curl
する。
$ curl -X POST -d 'client_name=【任意のアプリ名】&redirect_uris=urn:ietf:wg:oauth:2.0:oob&scopes=read write follow' https://mstdn.jp/api/v1/apps
# 以下のような内容がレスポンスされる
{
"id": "000000",
"name": "【先程入力した「任意のアプリ名」】",
"website": null,
"redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
"client_id": "【クライアント ID】",
"client_secret": "【クライアント・シークレット】",
"vapid_key": "【Vapid Key・特に使わないので無視】"
}
続いて、レスポンス内容を組み合わせて次のような URL を構築し、その URL にブラウザでアクセスする。
https://mstdn.jp/oauth/authorize?client_id=【クライアント ID】&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=read%20write%20follow
表示されたページで「承認」を押すと、「認証コード」が発行されるので控えておく。
そしたら次のような URL を組み立てて、再度 curl
を叩く。
$ curl -X POST -d 'grant_type=authorization_code&redirect_uri=urn:ietf:wg:oauth:2.0:oob&client_id=【クライアント ID】&client_secret=【クライアント・シークレット】&code=【ブラウザで発行した「認証コード」】' https://mstdn.jp/oauth/token
# 次のような内容がレスポンスされる
{
"access_token": "【Access Token】",
"token_type": "Bearer",
"scope": "read write follow",
"created_at": 1500000000
}
こうして Access Token が発行できたので、コレを控えておく。
ココまでやると、マストドンの設定画面の「アカウント」→「認証済アプリ」に、作成したアプリの情報が表示される。「開発」の「アプリ」の方には何も表示されない。
IFTTT の Applet を作成する
Access Token が用意できたら、IFTTT の Applet を作成していく。
- If That
- 「RSS Feed」→「New feed item」を選択し、RSS フィードの URL を指定する
- Then This
- 「Webhooks」→「Make a web request」を選択する
- URL :
https://mstdn.jp/api/v1/statuses
- Method : POST
- Content Type :
application/x-www-form-urlencoded
- Body :
access_token=【Access Token】&status=<<<{{EntryTitle}}>>> {{EntryUrl}}&visibility=public
IFTTT の画面上は << >>
(2重の山カッコ) で囲むと URI エンコード (エスケープ) できる、といった記載があるが、実際は <<< >>>
(3重の山カッコ) でないといけないらしい。
mstdn.jp
は IFTTT からのリクエストを拒否している模様
本来はこのように設定すれば、RSS フィードが更新された時に、Mastodon API を使ってトゥートされるはずなのだが、mstdn.jp
へのリクエストは 403 エラーになってしまい、うまくいかなかった。
どうやら mstdn.jp
側が IFTTT からのリクエストを拒否しているようで、避けられない。同じ Access Token を使って curl
で投げたり iOS ショートカットに組み込んだりする分には正常に動作するので、IFTTT だけが拒否されているようだ。
GAS を経由して送信する
ということで、mstdn.jp
にトゥートする場合は、
- RSS フィードの更新 → IFTTT で検知 → GAS に情報連携 → GAS から Mastodon API をコールしてトゥート
という手順にしてみる。
まず GAS を作成し、次のようなコードを作成する。
function doPost(e) {
try {
// JSON パースする (パラメータがない場合はココで例外が発生する)
const params = JSON.parse(e.postData.getDataAsString());
// IFTTT からの連携フラグがない場合、投稿文字列がない場合は何もしない
if(params.post_from !== 'ifttt' || params.status == null || params.status === '') {
return ContentService.createTextOutput(JSON.stringify({ error: 'Invalid Parameter' })).setMimeType(ContentService.MimeType.JSON);
}
const result = UrlFetchApp.fetch('https://mstdn.jp/api/v1/statuses', {
'method': 'POST',
'payload': {
'access_token': '【アクセストークンを指定する】',
'status' : params.status,
'visibility' : 'public'
}
});
Logger.log(result);
return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
}
catch(error) {
Logger.log(error);
return ContentService.createTextOutput(JSON.stringify({ error: error })).setMimeType(ContentService.MimeType.JSON);
}
}
コードを記述したら「公開」→「ウェブアプリケーションとして導入」を選択し、次のように指定する。
- Execute the app as: 「Me (【自分の Gmail アドレス】)」
- Who has access to the app: 「Anyone, even anonymous」
初回のみ謎のダイアログが出るが、気にせず承認し、URL を発行する。
そしたら IFTTT の Applet を次のように設定する。
- If That
- 「RSS Feed」→「New feed item」を選択し、RSS フィードの URL を指定する
- Then This
- 「Webhooks」→「Make a web request」を選択する
- URL : 【先程発行した GAS の URL】
- Method : POST
- Content Type :
application/json
- Body :
{ "post_from": "ifttt", "status": "{{EntryTitle}} {{EntryUrl}}" }
GAS の URL に向けて JSON を POST するよう書き換えている。その際、自分で用意した post_from
というパラメータによって、一応余計な POST を拒否するように GAS 側で制御している。
コレで IFTTT 側も準備 OK。ただ、GAS はスクリプト実行後に 302 をレスポンスするので、IFTTT の Activity 的にはエラー扱いになってしまうのが残念なところ。まぁトゥートは正常にできているし、コレで良しとする。
参考文献
- ブログの記事を投稿したらMastodonでトゥートする(IFTTT使用) - ぼくにがうりくん。 … 主にコチラが参考になった
- How to toot via IFTTT webhook · GitHub
- Atsushi's Homepage 〜 Mastodon API を使ってみる
- apps - Mastodon documentation
- Twitter の投稿を IFTTT で Mastodon へ転送する。 - Qiita
- IFTTTでif `Google Assistant` then `Webhook`でBad Requestが発生したときの対応メモ - Qiita< >>>` が正しいらしい
- IFTTTとGASを連携させると夢が広がる!今すぐ連携させるぞ - ポンコツエンジニアのごじゃっぺ開発日記。
- IFTTT→GAS→PushBulletで通知を受け取る | 株式会社イーガオ
- IFTTTのアクションをGoogle Apps ScriptにしてIFTTTを拡張する。 - Qiita
- IFTTTのWebhookをGASのPOSTで受け取るときのパラメータ覚書 - Qiita
- GASのdoPost関数をcurlでテストする時リダイレクトが必要なら-Xオプションを使わない - Qiita
- Google Apps Script - GASへのアクセスに対してJSONをコールバック|teratail
- GASへデータをPOSTし結果をjsonで受け取る時はリダイレクトされる - なんも分からないのでしらべた