KotlinでDiscord Botを始めてみる3 ~Embed実装編~

#はじめに
この記事は「KotlinでDiscord Botを始めてみる」第三弾です。
第一弾 : [環境構築と起動編](https://qiita.com/hisuie08/items/264456e505ab75f75bbe)
第二弾 : [シンプルなコマンド実装編](https://qiita.com/hisuie08/items/2cc32edbfa772af57a45)
も併せてどうぞ。

今回はタイトル通り、Embedメッセージの実装に挑戦します。
Embedを使うことでユーザーにとって使いやすいBotを作ることができます。
それではやっていきましょう。

###Gitリポジトリ
今回は[Chapter3ブランチ](https://github.com/hisuie08/kotlin-tutorial-bot/tree/chapter3)です。

# Embedの基本
Embedそのものの説明は過去記事で行っています。
[初心者に捧ぐDiscordのEmbed入門](https://qiita.com/hisuie08/items/5b63924156080694fc81)
当該記事はPythonをベースに解説した記事ですが、Embedそのものの仕様は言語関係なく同じなので、記事内のピックアップに託します。

- [Embed事始め](https://qiita.com/hisuie08/items/5b63924156080694fc81#embed%E4%BA%8B%E5%A7%8B%E3%82%81)
- [Embedのメリット](https://qiita.com/hisuie08/items/5b63924156080694fc81#embed%E3%81%AE%E3%83%A1%E3%83%AA%E3%83%83%E3%83%88)
- [Embedの構成要素](https://qiita.com/hisuie08/items/5b63924156080694fc81#embed%E3%81%AE%E6%A7%8B%E6%88%90%E8%A6%81%E7%B4%A0)


# ソースコード
前回の復習も兼ねて、コマンドでEmbedを返すBotを作っていきましょう。

```kotlin:main.kt
package ...
import net.dv8tion.jda.api.JDA
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.requests.GatewayIntent

//前回も使用したコマンドライブラリ
import com.jagrosh.jdautilities.command.Command
import com.jagrosh.jdautilities.command.CommandClientBuilder
import com.jagrosh.jdautilities.command.CommandEvent

//Embedを使うのに必要なimport
import net.dv8tion.jda.api.EmbedBuilder


class ShowEmbed:Command(){ //Embedを返すコマンド。
    init {
        this.name ="embed"
    }
    override fun execute(event : CommandEvent?) {

        //今回の肝。Embedの構築処理
        val embed = EmbedBuilder()//EmbedBuilderでインスタンスを作成して、後から中身をセットします。
            //タイトル文字列。第2引数にURLを入れるとタイトルを指定URLへのリンクにできます
            .setTitle("Tutorial Embed","https://example.com") 

            //Botの情報。タイトルと同じくリンクを指定できる他、第3引数にアイコン画像を指定できます。
            //今回は自分のアバターアイコンを指定しました。
            .setAuthor("tutorial bot","https://repo.exapmle.com/bot",event?.selfUser?.avatarUrl) 

            .appendDescription("Embed made with Kotlin JDA!!") //Embedの説明文
            .setColor(0x00ff00) //Embed左端の色を設定します。今回は緑。
            .addField("フィールド1","値1",false) //以下3つフィールドをセット
            .addField("フィールド2","値2",true)
            .addField("フィールド3","値3",true)
            .setThumbnail("https://image.example.com/thumbnail.png") //サムネイル(小さい画像)
            .setImage("https://image.example.com/main.png") //イメージ(大きい画像)

            //フッターには開発者情報を入れるといいでしょう。
            .setFooter("made by NashiroAoi","https://dev.exapmple.com/profile.png") 
            .build() //buildは一番最後の組み立て処理です。書き忘れないようにしましょう。

        event?.reply(embed) //送信はreplyにembedを渡してやるだけです。
    }
}

/**ここから下は前回までのと基本的に同じです。
addCommand()でShowEmbedを登録するのを忘れないようにしましょう。
**/
class BotClient{
    lateinit var jda: JDA
    private val commandPrefix = "/"
    
    fun main(token: String) {
        val commandClient = CommandClientBuilder()
            .setPrefix(commandPrefix)
            .setOwnerId("")
            .addCommand(ShowEmbed())
            .build()
        
        jda = JDABuilder.createLight(token,
            GatewayIntent.GUILD_MESSAGES)
            .addEventListeners(commandClient)
            .build()
    }
}


fun main() {
    val bot = BotClient()
    bot.main("トークン文字列")
}
```

上記コードはURLをプレースホルダーにしています。実際に使うときは少なくとも`thumbnail`,`image`,`setFooter()第2引数`の3つを実際の画像URLに置き換えて起動してください。

実行すると以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/0b2d5532-d88d-3a9a-49e9-1975eb403e72.png)

テスト用にお借りした画像URL
thumbnai: [WikiMedia Kotlinロゴ](https://upload.wikimedia.org/wikipedia/commons/thumb/7/74/Kotlin_Icon.png/600px-Kotlin_Icon.png)
image: [美雲このは壁紙](https://conoha.mikumo.com/wallpaper/)

## ローカルの画像をEmbedに埋め込む
Embedの画像はURLで指定する必要があるため、ローカルの画像を使うにはひと手間必要になります。

```kotlin:main.kt
...
import java.io.File

class ShowEmbedLocal:Command(){
    init {
        this.name ="embedlocal"
    }
    
    override fun execute(event : CommandEvent?) {
        val embed = EmbedBuilder().setTitle("Tutorial Embed with Local Image") //まずはEmbedを定義
        val file = File("ローカル画像ファイルのパス") //ローカルから画像ファイルを読み込み
        /**
        Discordでローカルの画像をアップロードするときは attachment:// URLを使います。
        ://以下は自由に決められるので、先程読み込んだ画像ファイルのファイル名を使いましょう。
        **/
        embed.setImage("attachment://${file.name}")

        /*Embed+画像 のような複雑なメッセージになるとreplyが使えません。
          ファイル送信に使うSendFileアクションは、embedを受け付けて一緒に送信することができます。
          一緒に送信されたembedが画像ファイルを求めた場合はファイルをembedにわたすこともできます。
          そこで、sendFileでの画像送信処理にembedをくっつけて送信しましょう。
        */
        event?.channel?.sendFile(file,file.name)?.embed(
                embed.build() //組み立てたembedを渡す。
             )?.queue() //送信処理
    }
}


```

`execute`3行目の`file`に任意の画像ファイルを指定して起動してみてください。

PC内に保存されていたミーム画像を読み込んで送ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398976/f17b2821-099d-b070-9c72-4546a6bd115b.png)

#最後に
ローカル画像のアップロードはなかなかに曲者です。
ですが`sendFile`はBotにファイルを送信させるという非常に重要な機能を提供しています。
ぜひとも習得し、使いこなしたいところです。

~~次回の内容はまだ決めていませんが、~~リクエストあればコメント頂ければ可能な限りお応えします。

それでは今回もお付き合いいただきありがとうございました。

次回: [Herokuへのホスト編](https://qiita.com/hisuie08/items/7e70edd7c2922fd020c2)