無料でdiscordBotっぽいことする

# はじめに
<!-- 発端や概要を記載 -->
※DiscordのWebhook機能＋GASを利用して、スプシの編集を検知して通知するBotっぽいことをするだけなのでBotではないです。

- 簡単に実装できる
- 毎回ローカルで立ち上げたりなどしなくていい
- 日常で使える


をテーマに考えていたため、

- 環境構築もGit操作もコンパイルもない、お金もかからない。
- 書くだけでデプロイなど必要ない。
- Googleのサービスを起点にSNSに通知するできるのでHelloWorld!を出すよりは実用的。

ということでこちらの記事を作成します。

# 準備
- アカウント作成
    - discord
    - google
- 自分が管理者のdiscordサーバー作成
    - 管理者じゃなくとも権限があれば良いのですが、そこの説明は割愛。
    - また、この記事の内容でサーバーに不利益が起こっても責任は負いませんのでよくわからない場合は新規サーバーを作成してそこで試したほうが良いです。
- スプレッドシートの作成
    - こちらも同様に分からなければとりあえず新規のものを作成したほうが良いです。

<!-- 各チャプター -->
# discordのWebhook設定
サーバ名右側の下向き矢印からメニューを開いて「サーバー設定」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/fe6a6110-2b69-7058-afa8-8fe2ef1a1d9e.png)

「ウェブフックを作成」を選択。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/16230747-c6e4-9b1f-6aed-6cfa69e433cf.png)

個々では他に、「新しいウェブフック」を選択したら追加されたウェブフックを選択して名前の変更と、通知を行うテキストチャンネルの選択ができます。

ウェブフックURLをコピーを選択してURLが作成できればウェブフックの準備は一旦終了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/7fbf2312-266b-7bec-52cc-8f310ac8cee6.png)

ここでアイコンや、名前を変更しなくとも通知時に送信者の名前はカスタムできるので変更してもしなくてもどちらでもいいですが、チャンネルはもし共有のサーバーであればBot用テキストチャンネルを作成してそこに設定しておいたほうが通知が邪魔にならないので無難です。　

# スプシとGas作成

スプレッドシートの作成は割愛。

スプレッドシートが作成できたらメニューの「拡張機能」を開いて「Apps Script」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/dc12f336-b383-3808-574f-38f304f3c3f6.png)

### スクリプトプロパティ(環境変数) 
Apps Scriptのページが開けたらまずスクリプトプロパティの登録を行います。
スクリプトプロパティはGASにおける環境変数というもので、これを利用することでパスワードやアクセスキー、ウェブフックのURLのような人目に晒したくない情報をコードにそのまま記載するよりも安全に使用することができます。

サイドメニューから「プロジェクトの設定」を選択し、
先程取得したウェブフックURLとプロパティ名を入力します。

プロパティ名は何でも良いですが、今回は`DISCORD_WEB_HOOK_URL`とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/d51b149e-cda0-78e0-ac2c-6ee583cd0f92.png)

### GAS
事前準備が終了したので、下記のような形でコードを書いて行きます。
`message`の`username`と`avatar_url`は設定しなければウェブフック作成時に設定したものが使われるだけなので、こだわりがなければなくても良いです。
```javascript
function onSheetEdit() {
  // 先程設定したウェブフックURLをスクリプトプロパティから取得
  const DISCORD_WEB_HOOK_URL = PropertiesService.getScriptProperties().getProperty("DISCORD_WEB_HOOK_URL");

  // 送信するメッセージを設定
  let message = {
    "username": "スプシBOT",// BOTの名前
    "avatar_url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3634175/237b480caf9ab0aefcdef16c9b30fe0257474c25/x_large.png?1701617742",// BOTのアイコン
    "content": "スプレッドシートが編集されました。", // メッセージ本文
  }
  
  // メッセージをウェブフックが受け取れる形に整形
  const param = {
    "method": "POST",
    "headers": { 'Content-type': "application/json" },
    "payload": JSON.stringify(message)
  }

  UrlFetchApp.fetch(DISCORD_WEB_HOOK_URL, param); // HTTPリクエストを行いレスポンスを戻すメソッド
}
```

### トリガー設定
ここまで来たら後は`onSheetEdit`を呼び出すトリガーを設定するだけです。

Gasには[Simple Triggers](https://developers.google.com/apps-script/guides/triggers?hl=ja)というものがデフォルトで存在しており、スクリプトの名称を規定のものにするだけで「スプシを開いたとき」や「編集した」ときをトリガーとしてスクリプトを実行することができます。
ですが、これらの権限は最も低いものとなっているため一部の操作を行うと画像のように権限エラーが発生してしまいます。
（`onEdit`内で`UrlFetchApp.fetch`を実行）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/e99d77c7-5a52-d460-2b35-45bb0ebe21a4.png)

そのため今回は`onEdit`を使用せずにトリガーを自作します。
サイドメニューから「トリガー」を選択し、画面右下の「トリガーを追加」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/3fdd7a6d-c558-2a30-927e-e20bf8f8762e.png)　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/0b6bf50a-f997-63de-c120-b087fa31aa2f.png)

 「実行する関数を選択」に先ほど作成した`onSheetEdit`を設定して、
 「イベントの種類を選択」では「編集時」に変更して「保存」します。
 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/25fb49e4-73cd-77be-71e9-a940893007aa.png)

「保存」を選択するとGoogleの認証画面が開くので、自分のアカウントを選択してください。
その後のポップアップは画面左下の「Advanced」を押して、
「Go to discordWebHook (unsafe)」を押すことで先に進めます。

よく読み問題がなければ実行してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/10456748-65b2-2127-df02-7ce9c0d8c076.png)

その次の画面でも内容をよく読み問題がなければ進んで
「Allow」を選択することでトリガーの設定は完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/ee2d442a-7a33-17c1-b677-76358dfaa389.png)

### 動作確認
スプレッドシートを編集してみます。
するとこのように設定したアイコンと名前で、メッセージが送信されれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/11392558-af88-8847-34bd-0eb6da5ea2fb.png)

もし送信されていない場合は、
サイドメニューの「実行数」からログが確認できるのでそれを参考に調査してみてください。

# おわりに
今回はお金をかけずに日常生活で利用可能なものを作成しました。
お金をかければもっとしっかりしたBotを作ることもできると思いますが、多機能なものが必要でなければこのぐらいチープに作ってみるのもいかがでしょうか。

# +α
### メッセージを豪華に
送信するメッセージにembed(埋め込みメッセージ)を使うことで画像をつけたりなど色々な装飾が可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3634175/db1e892e-8018-4380-485a-5bc2c09e48f0.png)

```javascript
function onSheetEdit() {
  // 先程設定したウェブフックURLをスクリプトプロパティから取得
  const DISCORD_WEB_HOOK_URL = PropertiesService.getScriptProperties().getProperty("DISCORD_WEB_HOOK_URL");

  // 送信するメッセージを設定
  // let message = {
  //   "username": "スプシBOT",// BOTの名前
  //   "avatar_url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3634175/237b480caf9ab0aefcdef16c9b30fe0257474c25/x_large.png?1701617742",// BOTのアイコン
  //   "content": "スプレッドシートが編集されました。", // メッセージ本文
  // }
  var message = {
    "username": "スプシBOT",
    "avatar_url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3634175/237b480caf9ab0aefcdef16c9b30fe0257474c25/x_large.png?1701617742",
    "content": "スプレッドシートが編集されました。",
    "embeds": [ // ここから埋め込みリンク
      {
        "title": "通知",
        "description": "編集通知です",
        "url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3634175/237b480caf9ab0aefcdef16c9b30fe0257474c25/x_large.png?1701617742",
        "timestamp": new Date(),
        "color": 5620992,
        "image": {
          "url": "https://s3-ap-northeast-1.amazonaws.com/qiita-image-store/0/3634175/237b480caf9ab0aefcdef16c9b30fe0257474c25/x_large.png?1701617742"
        },
      }
    ]
  };

  const param = {
    "method": "POST",
    "headers": { 'Content-type': "application/json" },
    "payload": JSON.stringify(message)
  }

  UrlFetchApp.fetch(DISCORD_WEB_HOOK_URL, param);
}
```
### スプシからもっと情報を取得
下記のようにonSheetEdit(e)に引数を持たせたりすることで変更があったシート名や、変更内容なども取得して送信することもできます。
```javascript
function onSheetEdit(e) {
  var sheet = e.source.getActiveSheet()
  console.log('シート名　 =', sheet.getName())
  console.log('変更範囲　 =', e.range)
  console.log('変更前の値 =', e.oldValue)
  console.log('変更後の値 =', e.value)
  // 以下略
}
```

# 参考文献
https://qiita.com/Eai/items/1165d08dce9f183eac74

https://qiita.com/mitama/items/e5fbf8306384c26cf42f