ふざけたタイトルですが下記の事をそれなりに丁寧にやります。
- IFTTT でツイートを取得、情報をスプレッドシートに書き込み
- GoogleAppsScript をTypeScriptで開発(+ 環境整備)
- DiscordのWebHookを利用し、botにメッセージを送らせる
ってことでやっていこう。
全文はかなり長いので、適宜必要な情報だけ拾ってください。
目次
使ったもの
- node.js 12.16.0
- Visual Sutudio Code 1.42.1
VSCodeとnode.jsはインストール済みのものとして進めていきます。丁寧とは
上記に関しては調べれば簡単にインストールができるので、ない場合はそうしてください。
具体的に何をするの?
初めに大体書きましたが、具体的には
IFTTTでTwitterのツイートを取得し、スプレッドシートに書き込み、
それをGASが検知して、ツイート内容を解析。
ツイート内容が "にゃーん" だったらDiscordへ猫の絵文字を流させる
という流れです。
ざっくり言うと、Twitterで社会性フィルターを感知するとDiscordに猫が駆けつけてくれるbotを作ります
GASの準備
GASってなんやねん
GoogleAppsScriptの略です。Googleアカウントさえあれば無料で使えます。
Googleのサーバー上で動作するスクリプトで、スプレッドシートやGmailなどGoogleの各種サービスを叩けます。
詳しくは調べればたくさん出てくるので、興味があればぜひ。
今回は無料で建てられるサーバーとしてIFTTTとDiscordの仲介役になってもらいます。
やっていき
GASを動かすためのいろいろを準備します。
セットアップ
今回はTypeScriptとClasp(GASをVSCodeで使うためのパッケージ)を用いて開発するので、clasp が Typescript をサポートした!を参考に必要なパッケージをインストールしていきます。
VSCode上でctrl+@
するとターミナルが開くので、そちらにコマンドを入れていきましょう。
$ mkdir nyan-bot
$ cd nyan-bot
$ npm init -y
$ npm install @google/clasp -D
$ npm install @types/google-apps-script -S
Typescriptはこちらでインストールしなくても@google/claspが依存しているので勝手にインストールされます。
トランスパイルはpushの際にclaspが勝手にやってくれるので、特にTypeScriptの諸々を設定する必要はありません。
ログイン
とりあえずgoogleアカウントへログインを済ませましょう
以下を実行するとブラウザが開き、必要情報を入力するとログインできます。
$ clasp login
GASを有効化
GoogleのフォームでGASを有効化しておかないと一部コマンドが使えないので、GASを過去に一回も使ったことがない人は
https://script.google.com/home/usersettings
にアクセスしてGoogleAppsScriptAPIをオンにしてきてください。
スクリプトとスプレッドシートを作成
ログインを済ませたらGASのスクリプトを作成します。
今回はスプレッドシートを使うので、以下のコマンドを実行したら
"Create which script?" にはsheetsと答えましょう
$ clasp create
ここまで正しく工程を踏めていれば以下のようにスクリプトとスプレッドシートのリンクが吐き出されます
扱いやすいようにフォルダと設定を整理
.clasp.jsonにrootDir
を設定することで、rootDir
で指定したディレクトリ以下のみがGASへpushされるようになります。
{
"scriptId":"xxxxxxxxxxxxxxxxxx-xxxx",
"rootDir": "./src"
}
以下の様なフォルダ構成にします。
pushの際、 appsscript.json を含めないといけないため、appsscript.json は必ずrootDirで指定したフォルダ以下に移動しておいてください。
nyan-bot/
├── .clasp.json
├── node_modules/
├── package-lock.json
├── package.json
|
├── node_modules
└── src
└─ ts
└─ appsscript.json
ひとまずGASのセットアップは終わりです。お疲れ様。
GASのテスト
セットアップが終わったので、まずは動作のチェックをします
.tsファイルを作る
以下のmain.ts ファイルを src/ts 下に作ります
function TestAction()
{
//アクティブなスプレッドシートを取得する
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
//一番初めのシートを取得する
const firstSheet = spreadSheet.getSheets()[0];
//セルに書き込む
firstSheet.appendRow(["こんにちは世界","Hello World","なんでプログラマすぐあいさつするん?"]);
};
GASへpush
以下のコマンドでpushできます
$ clasp push
pushしたらGASへ確認しに行きましょう。
URLで飛んでもいいですが、下記のコマンドでもアクセスできます。
$ clasp open
pushがうまくいっていればトランスパイルされた main.gs と再会できます
.gsとありますが、言語は JavaCusoript JavaScriptです
実行
GASは関数単位で実行されます。
電球マークの隣が TestAction になっていると思いますが、ここのリストに実行可能な関数名が列挙されます。
今回実行するのはそのまま TestAction なので、その左にある三角マークを押して実行しましょう。
関数内にスプレッドシートをいじる処理があるので、初めて実行する時は許可を求められます。
とりあえずはいはい言って許可を出します。
実行後、スプレッドシートに以下の様に書き込まれていれば成功です。
GASの準備は一通り完了。次はIFTTTに移ります。
IFTTTとやり取りをするための準備
といいましたが、先にスプレッドシート側の受け入れ準備をします。
シートを整理
IFTTTからツイート内容を受け取るシートRecvTweet
と、
GASのログを出力するシートLog
をそれぞれ用意しておきます。
スプレッドシートのパスを変更
また、スプレッドシートは現状Googleドライブのルートディレクトリに直置きされているので、IFTTTフォルダを作ってその中に放り込んでおきます。
(IFTTTでスプレッドシートのパスを選択する際、ルートディレクトリが選べないので)
これで準備は完了。IFTTTへ移りましょう
IFTTTを設定
IFTTTってなんやねん
イフトと読みます。IF This Then That(もし、これをしたらあれをする)の略です。
この子はInstagram、Twitter、Googleドライブなどのプラットフォームの仲介をしてくれます。
TwitterでツイートしたらGoogleドライブのスプレッドシートに書き込む、みたいなことができます。便利ですね。
ということでそれを利用します。
やっていき2
IFTTTの設定はこの記事を参考にしました
こちらを参考に、ツイートを感知してスプレッドシートへ書き込む機構を作ります。
まずはIFTTT にアクセスしてログインしましょう
Googleアカウントでログインできるので、アカウントがなくても簡単に入れます。
レシピを作成
Twitter側の設定
Create後、以下の様な画面になるので、If This Then That の発火条件に当たる [+]This をクリックしましょう。
クリックすると大量のプラットフォームが出てくるので、その中からTwitterを選びます。
マウスホイールを虐めながらTwitterを探すのもいいですが、Search servicesを利用した方がマウスホイールにやさしいです。
Twitterを選んだら、次はトリガー(発火条件)を選びます。
今回は自分がツイートしたときに発火して欲しいので、左上の New tweets by you を選択し、
Create Trrigerしましょう。
これで This、発火条件は設定完了です。
スプレッドシート側の設定
続いて [+]That をクリックしてアクションを設定しましょう。
さっきのTwitterと同じようにして、今度はGoogleSheetsを選びます。
スプレッドシートの更新を見てGASを起動するので、TriggerはUpdate cell in spreadsheetにします。
するとActionの設定が出てきます。項目は以下の通り。
Drive folder path
: 書き込みたいスプレッドシートのGoogleドライブ上のパス
Spreadsheet name
: 書き込みたいシートの名前
Which cell?
: 書き込むセル番地
Value
:書き込む内容。Add ingredientを押すと、Twitterからの情報を選べるので、Text(本文)とLinkToTweet(ツイートへのリンク)を選んでおきます。
以下のように設定したらCreate action。
後はFinishをクリックで終了。
動作テスト
動作させるために、先ほど作ったレシピをConnentさせておく
下のトグルスイッチに"Connected"と表示されてたらokです
This(Twitter) の動作チェック
[+]This でTwitterを選んだ時にログインしたアカウントでツイートしてみましょう。
ではIFTTTがツイートを拾えているか確認しに行きましょう。
先ほど作ったレシピのSettingから、View activityを開きます。
ツイートの内容が拾えていれば以下の様に表示されいます。
ただ、ツイートしてから拾うまでのラグがまちまちのため、しばらく待たないと出て来ないことが多いです
ここで表示されていない場合は、記事を遡りつつ以下の可能性を考慮してみてください
- IFTTTが拾うのに失敗している(何度かツイートしてみてください)
- Connectしてない(IFTTTのレシピがConnectedになってるか確認してください)
- ツイートするアカウントを間違えている
That(スプレッドシート)の動作チェック
GASのスプレッドシートを開いて確認してください。
一番目のシートのA1にツイート内容とリンクが入力されていればokです
ここで、GASのスプレッドシートではなく新しくスプレッドシートが生成されてしまっている場合はスプレッドシートの配置、もしくはIFTTTのスプレッドシートのパス設定が間違っています。
ここまでうまくいっていればIFTTTの準備は終わり。お疲れ様です
DiscordのBot準備
さて、入力側の準備が終わったので今度は出力側の準備をしましょう。
BotといってもWevhookというものを使った機構なので、よく使うサーバーに呼び込んで使うものとはちょっと違います。
Webhookってなんやねん
こちらの記事に詳しく書かれています
とりあえずは他のアプリケーションとやりとりするための機構だと思ってもらえればokです。
やっていき3
派遣する猫が迷わないようにします。
もとい、サーバーのWebhookを作成します
こちらの記事を参考にしました。
サーバーの準備
Webhookを作成するにはサーバーでの権限が必要です。
他人のサーバーで猫を受け取りたい場合は場合は管理人に相談して権限をもらってください。
もしくは自分でサーバーを立てましょう。
テキストを流すチャンネルの準備
Webhookの作成
サーバーの設定を開き、Webhookを作成します。
サーバーの設定にウェブフック
の項目がない場合はそのサーバーでの権限がない状態なのでどうにかしてください。
Webhookの設定
Webhookを作成したら設定が開くので、お好みの情報を入力してください。
猫を受け取った時、ウェブフックのアイコン
とお名前
を使ったBotがチャンネル
にメッセージを送ってくれます。
また、一番下のウェブフックURL
はGASからDiscordにメッセージを送るのに使うため、控えておいてください。
とりあえず私はこんな感じの設定にしました
保存を押せばDiscordの受け入れ準備は完了です
GASでDiscordへメッセージを送る
Discord側の受け入れ準備は終わったので、GASからメッセージを送りこめるようにします
やっていき4
VSCodeで、GASの準備で作ったプロジェクトを開いてください。
以下の様なフォルダ構成でやっていきます
各ファイルについてはこれから説明していきます
nyan-bot/
├── .clasp.json
├── node_modules/
├── package-lock.json
├── package.json
|
├── node_modules
└── src
├─ ts
| ├─ discord
| | └─ IDiscordSendParameters.ts
| | └─ IDiscordWebhookPayload.ts
| | └─ WebhookSender.ts
| └─ gas
| └─ SpreadSheetUtil.ts
└─ main.ts
└─ appsscript.json
ログ出力を実装
簡単にスプレッドシートにログを出す機構を先に作っておきます
export default class SpreadSheetUtil
{
//テキストのログ書き込み
public static WriteToLogSheet = (text: string) => {
//スプレッドシートを取得
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
//シート`Log`を取得
const sheet = spreadSheet.getSheetByName("Log");
//シート`Log`の最終行にtextを書き込み
sheet.appendRow([text]);
};
//HTTPResponse用のログ書き込み
public static WriteResponseToLogSheet = (
response: GoogleAppsScript.URL_Fetch.HTTPResponse
) => {
SpreadSheetUtil.WriteToLogSheet(
`[${response.getResponseCode()}] ${response.getContentText()}`
);
};
}
SpreadSheetUtil.WriteToLogSheet("ログ")
で、スプレッドシートのLogにログが出せます。
テストしてみましょう。
main.tsをいじってGASにpushします
import SpreadSheetUtil from "./gas/SpreadSheetUtil";
function LogTest()
{
SpreadSheetUtil.WriteToLogSheet("丸太テスト");
};
実行して、スプレッドシートのLog
に出力されていれば成功です。
Discordのメッセージ型を実装
Discordにメッセージを送らせる、と言っても普通に送ってもWebhook君には理解できません。
Jsonで送る必要があります。
ということでこちらの記事を参考にメッセージInterfaceを作ります。
各ステートの詳細は参考記事の方を見てください。
export default interface IDiscordWebhookPayload {
username?: string;
avatar_url?: string;
content?: string;
embeds?: [
{
title?: string;
description?: string;
url?: string;
timestamp?: string;
color?: number;
footer?: {
text?: string;
icon_url?: string;
};
image?: {
url?: string;
};
thumbnail?: {
url?: string;
};
author?: {
name?: string;
url?: string;
icon_url?: string;
};
fields?: {
name?: string;
value?: string;
inline?: boolean;
}[];
}
];
}
DiscordのWebhookにPostリクエストを送る
メッセージの型も準備ができたので、いよいよDiscordにメッセージを送る機構を作っていきます。
HttpRequestパラメータを定義
初めにHttpRequestのパラメータ型を定義しておきます
export default interface IDiscordSendParameters
{
method: "get" | "delete" | "patch" | "post" | "put";
payload: string;
contentType: string,
muteHttpExceptions: boolean;
}
DiscordにPostリクエストを送る機構を実装
先ほどのパラメータを使ってDiscordにPostリクエストを送ります。
DiscordWebHookSender.webhookURL
にはDiscordのBot準備で取得したウェブフックURLを入力してください。
import IDiscordWebhookPayload from "./IDiscordWebhookPayload";
import IDiscordSendParameters from "./IDiscordSendParameters";
import SpreadSheetUtil from "../gas/SpreadSheetUtil";
export default class DiscordWebHookSender
{
//DiscordのウェブフックURL
public static webhookURL:string="https://discordapp.com/api/webhooks/xxxxxxxxxxxx/xxxxxxxxxxxxxxxxxxxx";
//Postプロセスを送る
public static Send(payload: IDiscordWebhookPayload):void
{
//Postリクエストのパラメータを作成
const params: IDiscordSendParameters = {
method: "post",
payload: JSON.stringify(payload),
contentType: 'application/json',
muteHttpExceptions: true //エラーを起こしたときに、エラーの代わりに内容をHttpResponseを返してくれます。
};
//ログに、Discordに送るパラメータを表示
SpreadSheetUtil.WriteToLogSheet("[Throw Discord Message]: "+params.payload);
//DiscordにPostリクエストを送信
const response = UrlFetchApp.fetch(this.webhookURL, params);
//レスポンスをログに出力
SpreadSheetUtil.WriteResponseToLogSheet(response);
}
}
Discordにメッセージを送る!
さて、Discordにメッセージを送る準備が整いました。
ということで動作テストです。
main.tsをいかに書き換えてGASにpushしましょう
import SpreadSheetUtil from "./gas/SpreadSheetUtil";
import IDiscordWebhookPayload from "./discord/IDiscordWebhookPayload";
import DiscordWebHookSender from "./discord/WebhookSender";
function DiscordTest()
{
const payload:IDiscordWebhookPayload=
{
content:"にゃんにゃん"
};
DiscordWebHookSender.Send(payload);
};
実行して、Discordでメッセージが送られれば成功です。
合わせてログも確認しましょう。
うまく送信できてない場合は[204]
ではなくLogにエラーメッセージが出ます。
IFTTTとDiscordをつなげる!
準備は整った!あとはスプレッドシートに書きこまれるツイートを感知して、Discordに猫を派遣するのみです
スプレッドシートに書き込まれたツイートを読み込む機能を実装
ts:SpreadSheetUtil.tsに、スプレッドシートに書き込まれたツイートを読み込む機能、ReadRecvTweetを追加します
export default class SpreadSheetUtil
{
//テキストのログ書き込み
public static WriteToLogSheet = (text: string) => {
//スプレッドシートを取得
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
//シート`Log`を取得
const sheet = spreadSheet.getSheetByName("Log");
//シート`Log`の最終行にtextを書き込み
sheet.appendRow([text]);
};
//HTTPResponse用のログ書き込み
public static WriteResponseToLogSheet = (
response: GoogleAppsScript.URL_Fetch.HTTPResponse
) => {
SpreadSheetUtil.WriteToLogSheet(
`[${response.getResponseCode()}] ${response.getContentText()}`
);
};
//ツイートの読み込み
public static ReadRecvTweet():string {
//スプレッドシートを取得
const spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
//シート`RecvTweet`を取得
const sheet = spreadSheet.getSheetByName("RecvTweet");
//A1の内容を返す
return sheet.getRange("A1").getValue();
};
}
"にゃーん"かどうか判別して、猫を派遣する
main.tsに、スプレッドシートが変更されたときに走る処理を書きます。
ツイートの内容がにゃーん
なら猫を派遣し、それ以外が来た場合は派遣しません
import SpreadSheetUtil from "./gas/SpreadSheetUtil";
import IDiscordWebhookPayload from "./discord/IDiscordWebhookPayload";
import DiscordWebHookSender from "./discord/WebhookSender";
function SocialFilterCat()
{
//ツイートを取得
const tweet=SpreadSheetUtil.ReadRecvTweet();
//ツイートににゃーんが含まれるか解析
if(tweet.indexOf("にゃーん")===-1)
{
//社会性フィルターじゃないので返る
SpreadSheetUtil.WriteToLogSheet("<"+tweet+"> is not social filter");
return;
}
//URLを取得
const urlIndex=tweet.lastIndexOf("http://twitter.com/");
const tweetURL=tweet.substring(urlIndex);
const payload:IDiscordWebhookPayload=
{
content:":cat: \n"+tweetURL
};
DiscordWebHookSender.Send(payload);
};
できたらGASへpushして、SocialFilterCat
を実行します。
実行したらLogを確認してください。
"にゃーん"とツイートしていなければこういうLogが出ると思います
続いて、スプレッドシートの内容を"にゃーん"に変えて実行してみましょう。
可愛い猫ちゃんが派遣されました。
IFTTTからの書き込みを検知して自動で実行する
これで一応猫を派遣できるようにはなりましたが、
手動でしか動かないのでまだ流しそうめんを一人でやっているような感じです。
…ということでIFTTTからのツイート書き込みを検知して自動で動くようにしましょう
トリガーを設定
発火条件、トリガーを設定します。
GASの編集
->現在のプロジェクトのトリガー
を開きます
開いたらトリガーを追加をクリック。
以下の設定にして保存します。
スプレッドシートで変更が行われたらSocialFilterCat
が実行されるといった感じ。
鳴く!
…終わります。