Discord BotでYoutubeの情報を取得する

## 概要

PCではコピペでいいのですが、スマホユーザーはコピペをする際にアプリ離脱してしまうので、
リアルタイムでフレンドと情報の共有をするためにDiscordのみで完結するBotを作成します。

```
Discord.js v13
Node.js v22

```

# 1.Discord Botの準備

Discord Botを用意します
作成方法やトークンの払い出し方法は公式にも記載されているので割愛します。
[参考](https://note.com/exteoi/n/nf1c37cb26c41)

https://discord.com/developers/applications

# 2.Nodeのインストール

Nodeをインストールします
LTS版で問題ありません。

https://nodejs.org/en/

# 3.Discord.jsのインストール

コンソールより下記コマンドを叩きます。
```
# npm
npm i discord.js

# yarn
yarn add discord.js
```

# 4.Youtube APIの用意

① https://console.cloud.google.com/apis/dashboard

より「プロジェクトを作成」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/0676cedb-5f75-55ec-62d9-ca316fe1d32b.png)

② 任意のプロジェクト名を入力します。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/005be66b-d1ab-47e7-ca96-17274a4bcf28.png)

③ 作成後のプロジェクトから「APIとサービスを有効にする」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/1b35f940-dd32-522d-2537-1f6c3df571db.png)

④ API一覧画面の検索欄に「youtube」と入力すると「Youtube Data API v3」が出てくるので選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/9ee2c7b3-be76-f5ef-8405-c03b5fe2fe6c.png)

⑤ API詳細の「有効にする」ボタンをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/4bb6ca6c-c715-67a1-51c5-11a84151abc5.png)

⑥ API一覧から「Youtube Data API v3」の「認証情報を作成」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/7513e851-d1cc-7341-8ad9-6d8276c30a6a.png)

⑦ 「一般公開データ」を選択して「次へ」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/d8f52897-5319-3d44-6f6f-12c358586fd8.png)

⑧ 認証キーが払い出しされるのでメモしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/f0d47178-121c-ff28-40e6-1ce584399782.png)

# 5.Discord Botの実装

ひとまずindex.jsに記載します。
YouTubeとDiscordのキーとIDをそれぞれ書き換えます。
(運用する際にはキーなどはenvファイルに移動しましょう。)

```js

const { Client, Intents } = require('discord.js');
const client = new Client({
     intents: [
        Intents.FLAGS.GUILDS,
        Intents.FLAGS.GUILD_MESSAGES,
        Intents.FLAGS.GUILD_MEMBERS,
        Intents.FLAGS.GUILD_MESSAGE_REACTIONS]
    }
);

const fetch = require('node-fetch');

client.login("！！！DiscordのアプリケーションID！！！");

client.on('ready', async () => {
    console.log("deploy done...")
})
client.on('messageCreate', async msg => {

    const ytUrlPattern =/^http(s)?:\/\/(www.youtube.com\/watch\?|m.youtube.com\/watch\?|youtube.com\/watch\?)(\w+)|^https\:\/\/youtu.be\//

    if (!msg.content.match(ytUrlPattern)) {
        return
    }

    const key = "！！！YOUTUBEから払い出されたAPIキー！！！"
    const url = new URL(msg.content.replace("`","'").split(/\n/)[0]);
    const params = new URLSearchParams(url.search);
    const ytid = params.get("v") // 動画ID

    // 動画のURLに続けてメッセージを打つ場合があるのでケアする。
    if (!ytid) {
        var afterSlash = msg.content.split("/")
        ytid = afterSlash.slice(-1)[0]
        // 改行を含んでいたら更にsplit
        if (ytid.match(/\r\n|\n/)) {
            ytid = ytid.split(/\r\n|\n/)[0]
        }
    }

    // APIの固定URL
    var apiUrl = 'https://www.googleapis.com/youtube/v3/videos';
    // レスポンスに含める情報を指定
    // 増やしたい場合は個々に追加する
    // @see https://developers.google.com/youtube/v3/docs/search/list?hl=ja
    apiUrl += '?part=snippet,contentDetails,statistics,status'; 
        
    // 取得する動画IDを指定
    apiUrl += '&id=' + ytid; 
    // APIキーを指定
    apiUrl += '&key=' + key; 

    // 概要欄を取得する
    // その際には整形
    const response = await fetch(apiUrl, {
        method: 'get',
    })
    if (response.status == 200) {
        const json = await response.json()
        if (json.items.length) {
            if (json.items[0].snippet.description) {

                // DiscordのMarkDown記法で装飾する。
                const head = "```diff\n\n";
                const title = json.items[0].snippet.title
                const reporter = json.items[0].snippet.channelTitle
                const desc = json.items[0].snippet.description.replace("`","") + "\n\n" + "---動画の概要ここまで---"
                const publishedDate = new Date(json.items[0].snippet.publishedAt)
                 // // 装飾終わり
                 var hood = "```"

                 var replyEmb = {
                    author: {
                        name: reporter,
                    },
                    title: title,
                    url: `${msg.content.split(/\n/)[0]}`,
                    name: `投稿者:${reporter}`,
                    description: head + "---動画の概要ここから---\n\n" + desc + hood,
                    color: 0x2ecc71,
                    footer: {
                        text: `${publishedDate.getFullYear()}/${publishedDate.getMonth() + 1}/${publishedDate.getDate()} ${("0" + publishedDate.getHours()).slice(-2)}:${("0" + publishedDate.getMinutes()).slice(-2)}に投稿された動画`
                    },
                }
                await msg.reply({ embeds: [replyEmb] }).catch(err => console.log(err))
            }
            else {
                await msg.reply({ content: "この動画には概要欄に説明がありません!", ephemeral: true }).then((res) => {
                    discord.delete(msg, res, 3000)
                }).catch(err => console.log(err))
            }
        }
    }
})

```

# 6. 動作確認

コンソールより下記コマンドを叩きます。
```
npm run node
```

コンソールに「deploy done...」と出力されたら起動できているので、Botを参加させたサーバーで任意のYouTubeURLを打ち込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/fb7360ea-0638-e760-b94a-c104f377e5dc.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3932826/b57c4a87-204a-9c88-d5e5-6b4c1a99adef.png)

動画の概要欄などを取得することができました。