【Discord.js V14】Discord BOTにVCから１人分の音声を取得して、録音する機能を実装してみる

皆さん初めまして。Morichanと申します。
下記の※の記述を理解したうえで、記事を読んでください。

※DiscordBot開発初心者の書いた記事です。
（また、プログラミング自体、２年ほどのブランクあり）

BOTをVCに参加させるまでの流れに関しては、[別の記事](https://qiita.com/Mori-chan/items/2df4ad15adc79cf2a167)にまとめてあります。

関連記事：
* [【Windows11】Discord BOTを開発するための開発環境を整える。](https://qiita.com/Mori-chan/items/add6f63b04f70ff53732)
* [【Discord.js V14】Discord BOTにスラッシュコマンドを実装してみる](https://qiita.com/Mori-chan/items/2e869c0e2060b78f0380)
* [【Discord.js V14】Discord BOTをVCに参加させてみる](https://qiita.com/Mori-chan/items/2df4ad15adc79cf2a167)
* [【Discord.js V14】２つのBOTを別々のVCに参加させてみる](https://qiita.com/Mori-chan/items/7d598933753d0abe1b91)
* [【Discord.js V14】スラッシュコマンドのオプションで、既に選択済みの選択肢を２つ目の引数のリストから消す。](https://qiita.com/Mori-chan/items/89ad3245443f1e8ace07)
* [【Discord.js V14】Discord BOTにVCに音楽を流す機能を実装してみる](https://qiita.com/Mori-chan/items/84622c733dc43c419dc5)

## 目次
1. [開発環境](#開発環境)
2. [VCから１人分の音声を取得して、録音してみる](#vcから１人分の音声を取得して録音してみる)
3. [関連記事](#関連記事)


## 開発環境
OS (Windows11)
discord.js (14.7.1)
node.js (18.13.0)
npm (8.19.3)
@discordjs/voice (^0.14.0)




## VCから１人分の音声を取得して、録音してみる
Listener-botで音声を取得して、ファイルに書き出す処理を実装する。

* `index.js`内部のBOT(今回はListener-bot)の記述を改変する。
```
// GatewayIntentBits.GuildVoiceStatesを追加しないと、VCに入ってから音を取得したり流したりなどの処理ができない。
const client1 = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates] });
```

* `join.js`から、VCの情報を受け渡すコードを改変。
```
			await interaction.reply('VCに参加しました！');
			// return connection2; // ここを改変
            return [connection1, connection2];
		}
		else {
			await interaction.reply('BOTを参加させるVCを指定してください！');
		}
	},
};
```
* `index.js`でコマンドの判定を行い、commandの値が、
recordの時、connection1を`record.js`に受け渡し、
playの時、connection2を`play.js`に受け渡す。

```
// let connection = null; // ここを改変
let connection = [];

---（以下略）---

	try {
        // コマンドを実行
		if (interaction.commandName === 'join') {
			connection = await command.execute(interaction, client1, client2);
		}
        else if (interaction.commandName === 'record') { // ここを改変
			await command.execute(interaction, connection[0]);
		}
		else if (interaction.commandName === 'play') {
			await command.execute(interaction, connection[1]); // ここを改変
		}
		else {
			await command.execute(interaction);
		}
	} catch (error) {
		console.error(error);
		await interaction.reply({ content: 'コマンドを実行中にエラーが発生しました。', ephemeral: true });
	}
});

---（以下略）---
```

* 新しく`record.js`を作成。中身を記述。
```
const { SlashCommandBuilder } = require('discord.js');
const stream = require('stream');
const fs = require('fs');
const { EndBehaviorType } = require('@discordjs/voice');
module.exports = {
	data: new SlashCommandBuilder()
        // コマンドの名前
		.setName('record')
        // コマンドの説明文
		.setDescription('VCで音声を録音します。'),
	async execute(interaction, connection) {
		connection.receiver.speaking.on('start', (userId) => {
            const audio = connection.receiver.subscribe(userId, {
                end: {
                    behavior: EndBehaviorType.AfterSilence,
                    duration: 100,
                },
            });
            var filename = './rec/'.concat(Date.now(), '-').concat(userId, '.dat');
            var out = fs.createWriteStream(filename);
            stream.pipeline(audio, out, function (err) {
                if (err) {
                    console.warn(`❌ Error recording file ${filename} - ${err.message}`);
                } else {
                    console.log(`✅ Recorded ${filename}`);
                }
            });
        });
        await interaction.reply('VCの録音を開始します！');
	},
};
```

* ルートディレクトリに`rec`フォルダを作成し、
`node deploy-commands.js`、`node index.js`を行い、Discordでコマンド`/join`と`/record`を入力。
Listener-botのいるVCにしゃべると……
無事recフォルダの中に録音されたファイルが作製されました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3109638/c4329d61-e29a-9c50-8d26-19e8b2f8315e.png)


* 複数人での会話を録音したい場合は、[別の記事](https://qiita.com/Mori-chan/items/e9ced87c0d68a9eb2a9a)で使っている、npmのaudio-mixerを使えば取得できるはずです。

## 関連記事
* [【Windows11】Discord BOTを開発するための開発環境を整える。](https://qiita.com/Mori-chan/items/add6f63b04f70ff53732)
* [【Discord.js V14】Discord BOTにスラッシュコマンドを実装してみる](https://qiita.com/Mori-chan/items/2e869c0e2060b78f0380)
* [【Discord.js V14】Discord BOTをVCに参加させてみる](https://qiita.com/Mori-chan/items/2df4ad15adc79cf2a167)
* [【Discord.js V14】２つのBOTを別々のVCに参加させてみる](https://qiita.com/Mori-chan/items/7d598933753d0abe1b91)
* [【Discord.js V14】スラッシュコマンドのオプションで、既に選択済みの選択肢を２つ目の引数のリストから消す。](https://qiita.com/Mori-chan/items/89ad3245443f1e8ace07)
* [【Discord.js V14】Discord BOTにVCに音楽を流す機能を実装してみる](https://qiita.com/Mori-chan/items/84622c733dc43c419dc5)
* 【Discord.js V14】Discord BOTにVCから１人分の音声を取得して、録音する機能を実装してみる
* [【Discord.js V14】VC１からVC２に音声をStreaming（中継）するBOTを作成する。](https://qiita.com/Mori-chan/items/e9ced87c0d68a9eb2a9a)
* [【Discord.js V14】取得するVCの音声をロールによって判別する](https://qiita.com/Mori-chan/items/41cd914bb9a93d930bff)