Docker上でDiscordのBotを動かす

# Docker上でDiscordのBotを動かす

## どんなBotを作った？

特定の人が、特定のVoice Channelに入室すると、入場曲を歌うBot

（Ruby, discordrb使用）

### なんのため？

ただの身内ネタです。
~~何の役にも立ちません。~~

## なんでDocker上で動かす？

* 環境非依存にする
* 環境構築の手間を省く
    * Rubyのインストール
    * 必要パッケージのインストール
* 最終的にはGoogle App Engine上にデプロイしたい
    * 詳細は別記事にて

## DiscordにBotを登録する

導入に関する情報はぐぐればたくさんあるので省略。

[イチからDiscord Bot。for Ruby。](https://qiita.com/deneola213/items/efaeb0f5c20d44608a71)とか。

## discordrbをインストールする

Gemfileに`gem 'discordrb'`を追加

```ruby:Gemfile
gem 'discordrb'
```

## 入場曲を準備する

入場曲をmp3形式で準備します。5~10秒くらいの長さがちょうどいいかと思います。
作業ディレクトリ直下においてもいいですが、ここでは`data`ディレクトリを作ってその中に入場曲を置くことにします。ファイル名は`entrance_music.mp3`とでもしておきます。

今のディレクトリ構成はこんな感じ。

```bash
$ ls
Gemfile		data		bot.rb
```

* 先程`gem discordrb`を追加した`Gemfile`
* `data`ディレクトリの中に`entrance_music.mp3`
* `bot.rb`はこれからコーディングするBot

## 入場曲を歌わせるコードを書く

```ruby:bot.rb
require 'discordrb'

bot = Discordrb::Bot.new token: '自分のトークン'

bot.voice_state_update from: 入場曲を流したいユーザのID, channel: 入場曲を流したいVoiceChannelのID, do |event|
    if event.old_channel.nil?
        voice_bot = bot.voice_connect 入場曲を流したいVoiceChannelのID
        voice_bot.play_file 'data/entrance_music.mp3'
        voice_bot.destroy
    end
end

bot.run
```

> **Note:**
ユーザやチャンネルのIDはそれぞれのアイコンを右クリックすると、`IDをコピー`というメニューがでます。

### 使用メソッドの概要
* `Bot#voice_state_update`    
    * ユーザのVoice Stateが変わったときに起きるイベント
    * `from:`でイベントを起こす人のフィルタリング
    * `channel:`でイベントを起こすチャンネルのフィルタリング
    * 詳細は[こちら](http://www.rubydoc.info/gems/discordrb/Discordrb/EventContainer#voice_state_update-instance_method)
* `Bot#voice_connect`
    * Voice Channelに接続(入室)する
    * 返り値の`Voice#VoiceBot`を操作することで音声ファイルを再生したり、チャンネルとの接続を切ったりできる
    * 詳細は[こちら](http://www.rubydoc.info/gems/discordrb/Discordrb/Bot#voice_connect-instance_method)
* `VoiceBot#play_file`
    * 音声ファイルを再生する
    * 詳細は[こちら](http://www.rubydoc.info/gems/discordrb/Discordrb/Voice/VoiceBot#play_file-instance_method)
* `VoiceBot#destroy`
    * Voice Channelとの接続を切る。（退室する）
    * 詳細は[こちら](http://www.rubydoc.info/gems/discordrb/Discordrb/Voice/VoiceBot#destroy-instance_method)

参考：[discordrb Wiki](https://github.com/meew0/discordrb/wiki)

## Dockerをインストールする

[Install Docker](https://docs.docker.com/engine/installation/)から環境に応じてインストールします。

## Dockerfileを書く

* ここではRuby2.3.3のDocker Imageを使います
    * Ruby2.1以上ならなんでもいいと思います
* DiscordのBotに音声を扱わせるには以下のパッケージが必要なのでインストールします
    * libsodium
    * libopus
    * FFmpeg

```ruby:Dockerfile
FROM ruby:2.3.3

WORKDIR /app
COPY . /app

RUN apt-get update && apt-get install -y \
      libopus-dev \
      libsodium-dev \
      wget \
      xz-utils
RUN wget http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz \
      && tar Jxvf ./ffmpeg-release-64bit-static.tar.xz \
      && cp ./ffmpeg*64bit-static/ffmpeg /usr/local/bin/
RUN bundle install

CMD ["ruby", "bot.rb"]
```

## Botをビルドする

```bash
$ docker build -t entrance_music_bot
```

## Botを起動する


```bash
$ docker run entrance_music_bot
```

実行したあとに以下を確認できたら完成です。

* Botがオンラインになる
* 特定のユーザーが特定のVoice Channelに入ると、BotもそのVoice Channelに入室する
* 入場曲を歌う
* 歌い終わったらVoice Channelから退出する


## Future Work

これではPCを起動している間しかBotは動作しません。
そこで、Google Cloud Platform (App Engine)にデプロイして常時Botが動くようにします。（その記事はまた後日）

(追記)
[記事](https://qiita.com/otuhs_d/items/2cb2d798303041387475)書きました