【Discord.py】チャンネルを持ったカテゴリを作成する

#はじめに
###投稿者の自己紹介
どうもまぬおです！discord.pyでBotを開発しています。よろしくお願いします

###お知らせ
[Discord Bot Advent Calendar 2020](https://qiita.com/advent-calendar/2020/discordbot)
この記事はDiscord Bot Advent Calendarの2日目の記事です。ほかの方の投稿もぜひご覧になってください

[1日目](https://qiita.com/manuo/items/7f62dc2f1e0a801a0708)にも投稿しています。たくさんのViewありがとうございました！
良ければ、LGTMもよろしくお願いします！

###今回のテーマ
ボイスチャンネル2つ、テキストチャンネル1つが含まれたカテゴリをロビーとみなし、コマンドでそのロビーを作成するBotを作成します。良ければ最後までご覧ください

また、この記事はある程度Botを開発したことがある**中級者向け**の記事になっています。Botの開発を始める方法などは書きませんので注意してください
初心者の方には、別の方が書いていただいた初心者向けの記事があります
ボクもこの記事からDiscord Bot開発を勉強し始めましたのでおすすめです！

[PythonでDiscordBotを書く方法](https://qiita.com/1ntegrale9/items/9d570ef8175cf178468f)

##予備知識
今回の処理に使う予備知識を先に紹介します
###テキストチャンネルを作成する
テキストチャンネルは、文字で会話するチャンネルです
テキストチャンネル作成の関数は[Guild](https://discordpy.readthedocs.io/ja/latest/api.html#guild)が持っています

~~~ python3
#テキストチャンネルを作成する
await Guild.create_text_channel("テキストチャンネル")
~~~

###ボイスチャンネルを作成する
ボイスチャンネルは、声で会話するチャンネルです。VCとも言いますね
ボイスチャンネルも[Guild](https://discordpy.readthedocs.io/ja/latest/api.html#guild)の関数で作成します

~~~ python3
#ボイスチャンネルを作成する
await Guild.create_voice_channel("ボイスチャンネル")
~~~

###カテゴリを作成する
カテゴリは、チャンネルのグループ分けを行う仕組みです
チャンネル作成と同様に[Guild](https://discordpy.readthedocs.io/ja/latest/api.html#guild)の関数で作成します

~~~ python3
#カテゴリを作成する
await Guild.create_category("カテゴリ")
~~~

###各チャンネルをカテゴリに内包する
これにはいくつか方法がありますので、場合によって使い分けます
まずはそれぞれを作成して[後から設定する方法](https://discordpy.readthedocs.io/ja/latest/api.html#discord.TextChannel.edit)です。すでにあるチャンネルにカテゴリを設定するときに使えますね

~~~ python3
#チャンネルを作成する
TextChannel = await Guild.create_text_channel("テキストチャンネル")
VoiceChannel = await Guild.create_voice_channel("ボイスチャンネル")

#カテゴリを作成する
Category = await Guild.create_category("カテゴリ")

#カテゴリに内包する
await TextChannel.edit(category = Category)
await VoiceChannel.edit(category = Category)
~~~
次に、[チャンネル作成時にカテゴリを設定する方法](https://discordpy.readthedocs.io/ja/latest/api.html#discord.Guild.create_text_channel)です。

~~~ python3
# カテゴリを作成する
Category = await Guild.create_category("カテゴリ")

# チャンネルの作成時にカテゴリを設定する
await Guild.create_text_channel("テキストチャンネル", category = Category)
await Guild.create_voice_channel("ボイスチャンネル", category = Category)
~~~

最後に[カテゴリからチャンネルを作成する方法](https://discordpy.readthedocs.io/ja/latest/api.html#discord.CategoryChannel.create_text_channel)です。これが一番直感的でわかりやすいかもしれません
>A shortcut method to Guild.create_text_channel() to create a TextChannel in the category.
>A shortcut method to Guild.create_voice_channel() to create a VoiceChannel in the category.

今回はこの方法を使います


~~~ python3
# カテゴリを作成する
Category = await Guild.create_category("カテゴリ")

# チャンネルの作成時にカテゴリを設定する
await Category.create_text_channel("テキストチャンネル")
await Category.create_voice_channel("ボイスチャンネル")
~~~

##実装
###コマンドの受け付けを確認する
discord.pyでコマンドを受け付ける方法はいくつかありますが、今回は一番簡単な`discord.ext.commands`を使った方法でいきます
`discord.ext.commands`を使うと、コマンドの文字列をそのまま関数名にできるので簡単ですね。コマンドに続く文字列も取得できます

ロビー作成のコマンドは`!lobby ロビー名`にしました
まずは、コマンドがちゃんと実装できているか確認するためにprint()でロビー名を出力してみます

~~~python3
import discord
from discord.ext import commands

TOKEN = "TOKEN"

client = commands.Bot(command_prefix = "!")

@client.command()
async def lobby(ctx, arg):
    LobbyName = arg
    print(LobbyName)

client.run(TOKEN)
~~~
わかりにくいですが出力の様子です。ちゃんと指定したロビー名を取得できています
![result.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527954/c261db70-6ed3-7815-c200-a8cc0517a280.gif)
###コマンドの処理を実装する

それでは、実際に今回のBotのコードを書いていきます
コマンドの中の処理を変更し、ボイスチャンネル2つ、テキストチャンネル1つが含まれたカテゴリが作成される処理を記述します

~~~python3
import discord
from discord.ext import commands

TOKEN = "TOKEN"

client = commands.Bot(command_prefix = "!")

@client.command()
async def lobby(ctx, arg):
    LobbyName = arg
    Guild = ctx.guild

    # カテゴリを作成する
    Category = await Guild.create_category(LobbyName)

    # チャンネルの作成時にカテゴリを設定する
    await Category.create_text_channel("テキストチャンネル")
    await Category.create_voice_channel("ボイスチャンネル1")
    await Category.create_voice_channel("ボイスチャンネル2")

client.run(TOKEN)
~~~
結果はこんな感じです。コマンドで指定した名前のロビーが作成できていますね
![result2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/527954/4d6e9e4c-44a2-62ce-2fc7-8a1b4d0b4b35.gif)
ちなみに
`discord.ext.commands.errors.CommandInvokeError: Command raised an exception: Forbidden: 403 Forbidden (error code: 50013): Missing Permissions`
のエラーが出た場合は権限が足りていません
`Manage Channels`の権限をBotに与えると解決します
##おわりに
###増え続けるロビー
みなさんお気づきかと思いますが、今回の実装ではロビーを削除する機能がありませんので無尽蔵にロビーが増え続けます
削除するコマンドは、次回以降に紹介するかもしれません（しないかも）
チャンネルを作成する処理は、他の処理と組み合わせると便利な機能になりやすいです。ぜひ今回紹介した処理を参考にしてください
###おわりのあいさつ
ここまで読んでいただき、ありがとうございました
この記事がみなさんの開発に役立つと幸いです
それでは良いDiscord Bot開発ライフを！
###各種バージョン
Python3 : 3.6.9
Discord.py : 1.5.1