GoでDiscordの簡易botを作ろう

#はじめに
GoでDiscordのbotを作ろうとしたところ、日本語の記事が一切見あたらなかったので申し訳程度のメモですが、記そうと思います。

* 送信されたメッセージに応じて処理を行う。
* 通話チャンネルに出入りする。
* 通話チャンネルで音声入力を監視する。

を実装したbotを作っていきます。

#注意 (2020/05/21)
この記事は投稿してから数年が経過してるので、ライブラリの更新状況によっては仕様が変わっている可能性があります。多分ある程度参考にはなると思うんですが、もしエラーが出たら[ライブラリのgodoc](https://godoc.org/github.com/bwmarrin/discordgo)とかをチェックしてみてくださいね！！！！！

#Go側の準備
ライブラリは https://github.com/bwmarrin/discordgo を使います。

```
go get github.com/bwmarrin/discordgo
```
をしておいてください。

#Discord側の準備
1.まず[Discord-My Apps](https://discordapp.com/developers/applications/me)にアクセスして、NewAppボタンをクリック。
![dis.jpg](https://qiita-image-store.s3.amazonaws.com/0/143170/6d9eda9a-c370-ccf3-8d27-429c2e8fa88e.jpeg)

2.続いて、アプリケーションの名前(アイコン、アプリケーションの説明)を入力してCreateAppをクリック。
(ここでいうアプリケーションの名前がBotの名前になります)
<img width="855" alt="スクリーンショット 2017-08-03 11.29.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/143170/82b183db-971e-ee15-cfe1-5e76aaa65976.png">

3.Create a Bot UserをクリックしたのちYes, do itをクリックしてボットユーザーを作成！
<img width="751" alt="スクリーンショット 2017-08-03 11.32.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/143170/da7360fe-47bc-304f-b9c0-a6b7a90c16a8.png">

4.するとbotの詳細画面がでるので、

+ APP DETAILS以下の__ClientID__
+ APP BOT USERの_click to reveal_をクリックして表示される__Token__

を控えておきましょう。その後save changesで設定を保存しましょう

<img width="743" alt="スクリーンショット 2017-08-03 11.34.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/143170/ee5a0d7e-e023-8b37-119e-ec024a45ca25.png">

5.

```
https://discordapp.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot&permissions=0
```

に、`YOUR_CLIENT_ID`を手順4で控えたClient IDに置き換えてアクセスしましょう。
(上の画像なら342494499286679553と置き換える)
botを追加したいサーバーを選択して認証をクリック。
これでbotがサーバーに追加されました。
<img width="546" alt="スクリーンショット 2017-08-03 11.48.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/143170/01423325-9d3a-0e48-c6a8-f38d693e6056.png">

これで準備は整いました
#プログラム

以下プログラム本文です。

* YOUR_TOKEN
* YOUR_CLIENT_ID
* VOICE_CHANNEL_ID

を各々の値に変更して使用してください

```go:main.go
package main

import (
	"fmt"
	"time"
	"github.com/bwmarrin/discordgo"
	"log"
	"strings"
)

var(
    Token = "Bot YOUR_TOKEN" //"Bot"という接頭辞がないと401 unauthorizedエラーが起きます
    BotName = "<@YOUR_CLIENT_ID>"
    stopBot = make(chan bool)
    vcsession *discordgo.VoiceConnection
    HelloWorld = "!helloworld"
    ChannelVoiceJoin = "!vcjoin"
    ChannelVoiceLeave = "!vcleave"
)

func main() {
        //Discordのセッションを作成
	discord, err := discordgo.New()
	discord.Token = Token
	if err != nil {
		fmt.Println("Error logging in")
		fmt.Println(err)
	}

	discord.AddHandler(onMessageCreate) //全てのWSAPIイベントが発生した時のイベントハンドラを追加
	// websocketを開いてlistening開始
	err = discord.Open()
	if err != nil {
		fmt.Println(err)
	}
    defer discord.Close()

	fmt.Println("Listening...")
	<-stopBot //プログラムが終了しないようロック
	return
}

func onMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	
	if err != nil {
		log.Println("Error getting channel: ", err)
		return
	}
        fmt.Printf("%20s %20s %20s > %s\n", m.ChannelID, time.Now().Format(time.Stamp), m.Author.Username, m.Content)

    switch {
        case strings.HasPrefix(m.Content, fmt.Sprintf("%s %s", BotName, HelloWorld)):　//Bot宛に!helloworld コマンドが実行された時
            sendMessage(s, m.ChannelID, "Hello world！")

        case strings.HasPrefix(m.Content, fmt.Sprintf("%s %s", BotName, ChannelVoiceJoin)):

            //今いるサーバーのチャンネル情報の一覧を喋らせる処理を書いておきますね
                    //c, err := s.State.Channel(m.ChannelID) //チャンネル取得
		    //guildChannels, _ := s.GuildChannels(c.GuildID)
		    //var sendText string
		    //for _, a := range guildChannels{
			    //sendText += fmt.Sprintf("%vチャンネルの%v(IDは%v)\n", a.Type, a.Name, a.ID)
		    //}
		    //sendMessage(s, c, sendText) チャンネルの名前、ID、タイプ(通話orテキスト)をBOTが話す

            //VOICE CHANNEL IDには、botを参加させたい通話チャンネルのIDを代入してください
            //コメントアウトされた上記の処理を使うことでチャンネルIDを確認できます
            vcsession, _ = s.ChannelVoiceJoin(c.GuildID, "VOICE_CHANNEL_ID", false, false)
            vcsession.AddHandler(onVoiceReceived) //音声受信時のイベントハンドラ

        case strings.HasPrefix(m.Content, fmt.Sprintf("%s %s", BotName, ChannelVoiceLeave)):
            vcsession.Disconnect() //今いる通話チャンネルから抜ける
    }
}

//メッセージを受信した時の、声の初めと終わりにPrintされるようだ
func onVoiceReceived(vc *discordgo.VoiceConnection, vs *discordgo.VoiceSpeakingUpdate) {
    log.Print("しゃべったあああああ")
}

//メッセージを送信する関数
func sendMessage(s *discordgo.Session, channelID string, msg string) {
	_, err := s.ChannelMessageSend(c.ID, msg)

	log.Println(">>> " + msg)
	if err != nil {
		log.Println("Error sending message: ", err)
	}
}
```
#まとめ
以上GoでDiscordのBotをつくるための手順でした。
あとは[ドキュメント](https://gowalker.org/github.com/bwmarrin/discordgo)を見ながらお好みに改造してください！
質問がございましたらコメントにて教えてください。

本記事はあくまでも現状GoでDiscordのBotをつくる日本語の記事がなかったため、至らない部分があることを十分承知した上で書かせていただいたものです。英語の資料やコードを読める方はそちらを読んでいただくほうが賢明かと思います。
何かコードに関して、追加情報等ございましたら、コメントにて教えていただけると大変助かります。

# 追記
このライブラリにはdiscordのグループがあります。[https://discord.gg/0f1SbxBZjYoCtNPP](https://discord.gg/0f1SbxBZjYoCtNPP) (公用語は英語)

また、このライブラリの作者の方が[dgvoice](https://github.com/bwmarrin/dgvoice)というライブラリを作られていて、これを使うことでmp3ファイルの音源を通話チャンネルで流すことができます。