15
7

More than 3 years have passed since last update.

【Discord.py】Discord.py 1.5で追加されたIntentsを攻略する

Last updated at Posted at 2020-11-30

はじめに

投稿者の自己紹介

どうもまぬおです!discord.pyでBotを開発しています。よろしくお願いします

お知らせ

Discord Bot Advent Calendar 2020
この記事はDiscord Bot Advent Calendarの1日目の記事です。ほかの方の投稿もぜひご覧になってください

今回のテーマ

on_member_update()イベントを利用する際に、1.5で追加されたIntentsを設定する必要があったのでその経緯と解決について書きます
また、この記事はある程度Botを開発したことがある中級者向けの記事になっています。Botの開発を始める方法などは書きませんので注意してください
初心者の方には、別の方が書いていただいた初心者向けの記事があります
ボクもこの記事からDiscord Bot開発を勉強し始めましたのでおすすめです!

PythonでDiscordBotを書く方法

問題が起きた

ある日

メンバーに特定の役職が付与された時に、メンバーのニックネームを変更するBotを開発していました
役職の付与はZiraを使用しており、メンバーの役職が変更されたタイミングでニックネームを変更することができれば、仕様が満たされると考えました

on_member_update()を使う

on_member_update()は、メンバーの情報が更新されたときに呼び出されるイベントです

on_member_update()のAPIリファレンス

Member がプロフィールを編集したとき呼び出されます。
これらのうちひとつ以上が変更されたとき呼び出されます

  • ステータス
  • activity
  • ニックネーム
  • roles

これらのうち、rolesの変更がされたときにニックネームの設定をしようと思いました

書いたコード

これを踏まえて、イベントが呼ばれたらニックネームを変更するコードを書いてみます

import discord

TOKEN = "TOKEN"
ROLEID = ロールのID

client = discord.Client()

@client.event
async def on_member_update(before, after):
    Guild = before.guild
    Role = Guild.get_role(ROLEID)
    NickName = "ニックネーム"

    if not Role in before.roles and Role in after.roles:
        await after.edit(nick = NickName)

    if not Role in after.roles and Role in before.roles:
        await before.edit(nick = None) #Noneを代入することで初期化できます

client.run(TOKEN)

問題ないように見えますよね?
文法も間違っていませんし、実行してみるとエラーも出ません
しかし、このコードではこのイベントに入ることすらないのです
イベントの一番最初にprint()を書いてみましたが、出力はありませんでした

原因

何かが足りない

なにか見落としていると思いAPIを見直してみたところ、こんな一文が

This requires Intents.members to be enabled.

明らかにこれが足りなさそう
でも、Intentsとは何かを知りませんでした
以下リファレンスの引用です

Wraps up a Discord gateway intent flag.
Similar to Permissions, the properties provided are two way. You can set and retrieve individual bits using the properties as if they were regular bools.
To construct an object you can pass keyword arguments denoting the flags to enable or disable.
This is used to disable certain gateway features that are unnecessary to run your bot. To make use of this, it is passed to the intents keyword argument of Client.
バージョン 1.5 で追加.

どうやら、最新のver.1.5で追加された要素のようです
このIntentsを設定しないとmemberの更新が検知できないようですね
Intents.membersの項目の説明はこうなっています

members
Whether guild member related events are enabled.
This corresponds to the following events:

on_member_update() (nickname, roles)

Intentsのmembersの項目を有効にしたら行けそうです

Intentsを有効にしたコード

import discord

TOKEN = "TOKEN"
ROLEID = ロールのID

Intents = discord.Intents.default()
Intents.members = True
client = discord.Client(intents=Intents)

# client = discord.Client()

@client.event
async def on_member_update(before, after):
    Guild = before.guild
    Role = Guild.get_role(ROLEID)
    NickName = "ニックネーム"

    if not Role in before.roles and Role in after.roles:
        await after.edit(nick = NickName)

    if not Role in after.roles and Role in before.roles:
        await before.edit(nick = None) #Noneを代入することで初期化できます

client.run(TOKEN)

これで完璧でしょ!
...
と思いますよね?
しかし、まだ落とし穴があります
Intentsを設定することで実際にこのイベントを実行することはできていますが、こういうエラーが出ます
discord.errors.PrivilegedIntentsRequired: Shard ID None is requesting privileged intents that have not been explicitly enabled in the developer portal.
つまり、Intentsを利用するにはdeveloper portalで有効化する必要があるということです

本当に解決

Developer Portalで有効化する

そうと決まれば有効化です
Botの項目のSERVER MEMBERS INTENTを有効化します
スクリーンショット 2020-12-01 031459.png
ここを設定することで、特定のロールを付与した時にニックネームを変更する仕様を実装することができました
result.gif

おわりに

Intentsが必要なイベントがまだまだある

今回はon_member_update()イベントでIntentsが必要でしたが、APIを見る限りまだまだIntentsの設定が必要なイベントはありそうです
もしイベントが反応しない場合に遭遇したら、Intentsを見直してみるとよいかもしれません

おわりのあいさつ

ここまで読んでいただき、ありがとうございました
この記事がみなさんの開発に役立つと幸いです
それでは良いDiscord Bot開発ライフを!

各種バージョン

Python3 : 3.6.9
Discord.py : 1.5.1

15
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
7