質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
Discord

Discordは、ゲーマー向けのボイスチャットアプリです。チャット・通話がブラウザ上で利用可能で、個人専用サーバーも開設できます。通話中でも音楽を流したり、PC画面を共有できるなど多機能な点が特徴です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3037閲覧

Discord、合言葉BOTの制作

Go321123

総合スコア1

Discord

Discordは、ゲーマー向けのボイスチャットアプリです。チャット・通話がブラウザ上で利用可能で、個人専用サーバーも開設できます。通話中でも音楽を流したり、PC画面を共有できるなど多機能な点が特徴です。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/10/20 19:15

編集2021/10/23 11:31

実現したいこと

discord.py を使ってDiscordのDMで特定の言葉を入力すると、自動でチャンネルを閲覧可能になる役職(権限)を付与する、合言葉BOTを制作したいと思っているのですが、可能ですか?

DMで行うことに関して、サーバーのテキストチャンネルで合言葉を入力するとなると、他の参加者にも見えてしまう恐れがあると思ったので、出来ればDM内で行いたいという事です。

DM内にて 「?r ラーメン大好き」 と入力すると、ラーメン好き という役職が付与され、チャンネルが閲覧できるようになる

該当のソースコード

role_ID = 0 role = message.guild.get_role(role_ID) await user.add_roles(role)

これらを使ってメッセージを読み込むと役職付与する事が、DM内で出来るかどうか...
DMにこだわらなくても匿名で出来るのであれば教えてください

補正したソースコード

下記の回答を基に組んだソースコード

Python

1import discord 2from discord.ext.commands import Bot 3 4 5# discord.ext.commands.Botはdiscord.Clientのサブクラスなので 6# discord.Clientのメソッド(get_guild()とか)も使える 7bot = Bot(command_prefix='?') 8 9GUILD_ID = 0 10ROLE_ID = 0 11 12 13role = None 14 15 16@bot.event 17async def on_ready(): 18 guild = bot.get_guild(GUILD_ID) 19 role = guild.get_role(ROLE_ID) 20 21 22@bot.command(name='r') 23async def add_role(ctx, word): 24 if (role is not None 25 and isinstance(ctx.message.channel, discord.DMChannel) 26 and word == 'ラーメン大好き'): 27 await ctx.message.author.add_roles(role) 28 29 30bot.run('TOKEN')

###補正したソースコードのエラーコード

Pyhton

1Run flake8 --ignore=E302,E501 2./discordbot.py:19:5: F841 local variable 'role' is assigned to but never used 3./discordbot.py:25:9: W503 line break before binary operator 4./discordbot.py:26:13: W503 line break before binary operator 5Error: Process completed with exit code 1.

###HerokuのConfig Vars の設定
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

正直、discord.pyには詳しくありませんが、調べてみるとDMでも基本は普通のコマンドbotと変わらないようです。
ただしDMの場合、ctx.message.guildNoneになってしまうそうなので、事前にguildroleを取得しておきましょう。

また、DMChannelからのメッセージの場合、context.message.authorMemberではなくUserとなります。
Member.add_roles()を使うためにはguild.get_member(context.message.author.id)で改めて対応するMemberオブジェクトを取得する必要があります。
そして、guild.get_member()を使用するにはIntentsというオブジェクトを使ってオプションを設定してあげる必要があります。

以下のコードではトークンや合言葉など見られてはまずいものを環境変数から読み込むようにしていますので、HerokuのConfig Varsに適宜設定するか書き換えてください。

【追記】
add_role()の2つ目以降の引数に?rの引数が渡されるので、いくつ渡されてもいいように可変引数とし、引数がなかったり引数に渡されたフレーズが間違っていれば「合言葉が間違っています」と表示するようにしました。

python

1import discord 2from discord.ext.commands import Bot 3import os 4import traceback 5 6 7TOKEN = os.getenv('DISCORD_BOT_TOKEN') 8GUILD_ID = int(os.getenv('DISCORD_BOT_GUILD_ID')) 9ROLE_ID = int(os.getenv('DISCORD_BOT_ROLE_ID')) 10WORD = os.getenv('DISCORD_BOT_WORD') 11 12 13intents = discord.Intents.default() 14intents.members = True 15bot = Bot(command_prefix='?', intents=intents) 16 17 18guild = None 19role = None 20 21 22@bot.event 23async def on_ready(): 24 global guild 25 global role 26 guild = bot.get_guild(GUILD_ID) 27 role = guild.get_role(ROLE_ID) 28 29 30@bot.event 31async def on_command_error(ctx, error): 32 orig_error = getattr(error, "original", error) 33 error_msg = ''.join(traceback.TracebackException.from_exception(orig_error).format()) 34 await ctx.send(error_msg) 35 36 37def is_DM(message): 38 return isinstance(message.channel, discord.DMChannel) 39 40 41@bot.command(name='r') 42async def add_role(ctx, *args): 43 """DM経由かつ合言葉が合っていれば役職を付与""" 44 # 「?r あああ いいい」 → add_role(ctx, ['あああ', 'いいい']) → 'あああ いいい' 45 # 「?r」 → add_role(ctx, []) → '' 46 word = ' '.join(args) 47 if role is not None and is_DM(ctx.message) and word == WORD: 48 user = guild.get_member(ctx.message.author.id) 49 await ctx.send("役職を付与しました。") 50 await user.add_roles(role) 51 else: 52 await ctx.send('合言葉が間違っています。') 53 54bot.run(TOKEN)

Botの権限も重要です。
Discord Developer PotalでBotをサーバに登録するためのURLを生成するときにBotの権限を指定します。
Manage RolesやSend Messagesが必要になります(とりあえず全部与えて試していたので、もしかしたら他にも必要な権限があるかもしれません)。
同時に、2つあるインテントの設定もオンにしてください。
詳しくは以下の質問の回答が画像付きなのでおすすめです。

Discord - How to give my bot permissions. [Javascript] - Stack Overflow

その上で、サーバーの設定画面でBot用の権限(自動で作成されます)が他の権限よりも上に来るように設定しましょう。
これをしないと一部のユーザに対して操作できなくなったりするそうです。

参考:

以下、少し見にくいかもしれませんが、動作した環境の各種設定です。
権限はサーバの設定から変更することはできず、Botを導入するためのURLを生成するときにしか指定できませんので、変更したい場合は一度Botをサーバから削除して導入し直す必要があるようです。
Botの削除は「サーバの設定→Integrations→Bot名→Delete Integration」で可能です。

インテント
パーミッション1
パーミッション2
権限
権限の順番

以上、お役に立てれば幸いです

投稿2021/10/21 02:43

編集2021/10/24 23:55
fj68

総合スコア752

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Go321123

2021/10/21 20:26 編集

こちらの記事を参考に、Herokuのクラウドサーバーを使ってgithub上でソースを組み立てているせいなのか、このソースコードをそのまま使用してもエラーをはかれ上手くいきませんでした これ専用にコードを書き換えればいけるのだろうとは思いますが、知識が浅く見当がつかないです... https://qiita.com/1ntegrale9/items/aa4b373e8895273875a8 エラーコード ```Python Run flake8 --ignore=E302,E501 flake8 --ignore=E302,E501 shell: /usr/bin/bash -e {0} env: pythonLocation: /opt/hostedtoolcache/Python/3.8.12/x64 ./discordbot.py:31:23: E999 SyntaxError: invalid syntax Error: Process completed with exit code 1. ```
fj68

2021/10/22 01:47

すいません、if文のカッコを忘れていました。 回答を編集しました。 失礼しました。
Go321123

2021/10/22 10:21 編集

ありがとうございます! しかしデバッグした結果、前よりは良くなったものの、まだエラーがでますね... 編集したものを少し手を加えてエラーを極力少なくしたもの質問欄に書き加えました。(「補正したソースコード」の部分) エラーを見ると、 ・変数'role'が使われてない ・and の位置がおかしい ということがわかりますが、andに関しては https://teratail.com/questions/213385 これを参照すると正しく思えるのですが、、、
fj68

2021/10/22 10:24

エラーを見たところflake8を使われているようなので、flake8のスタイルに合うようソースを修正しました。 それから、on_ready()で「global role」するのを忘れていたので追記しました。 何度もすみません。
Go321123

2021/10/22 12:27 編集

ありがとうございます!何度もごめんなさい、 import os と、 import sys を入れると 「os、 sys は使われていません」とエラーが出て、削除したらエラーはなくなりました。 この場合だとBOTがオンライン状態にならず、’TOKEN’ の所を小文字したらオンラインになりました、、、 しかし肝心のDMを送信してもBOTは何も反応してくれませんね…
fj68

2021/10/22 12:36

import osとimport sysはデバッグのときに使ったものが残ってました、すいません。 反応してくれないのはなぜか、ちょっとわからないので調べてみますね!
fj68

2021/10/22 13:20

一つ確認なのですが、「bot.run('TOKEN')」の「'TOKEN'」のところは実際の有効なトークン文字列に変えて実行されていますか。 一応、確認させていただきたく。
Go321123

2021/10/22 13:47 編集

すいません、TOKENは大文字のままでもオンライン状態になりました。しかしうまく反応しないままですね TOKEN のところは有効なトークン文字列に変えていると思います。Discord Developer からBOTのTOKENをコピーして貼っています 加えてGUILD_ID と ROLE_ID も実際のものは差し替えています もしかして Discord Developer のインテントの設定を全てオンにしないと稼働しないんですかね?
fj68

2021/10/22 16:44

インテント以外にもいくつか知らないことがあったので、回答に追記してコードを修正しました。 ご確認ください。
Go321123

2021/10/22 18:32 編集

上記の通り行った結果、 デバッグした結果エラーは出ませんでしたが、BOTがオンラインになりませんね... 今度こそうまくいったと思ったのですが...
fj68

2021/10/22 18:30

BOTを一度サーバーから削除して(サーバの設定→Integrations→Bot名→Delete Integration)、パーミッションとインテグレーションを設定したURLからもう一度登録してみていただけませんか? 当方の環境では動作確認が取れておりまして、Go321123さんの環境と当方の環境との差異を埋めていけば動作するようになるのではと存じます。 参考になるよう、動作した環境の設定がわかるスクリーンショットを回答に追記しますね。
Go321123

2021/10/22 19:42

オフラインになってしまう原因がわかりました! Discord Developer でBOT_TOKEN を REGENERATE しており、 HerokuのConfig Vars の DISCORD_BOT_TOKEN のところTOKENのコードが古いままで、うまく起動してませんでした。新しいトークンを貼ったらうまくいきました。 しかし今度は稼働はしているのですが 「/r ラーメン大好き」とDMにうつと「Fail to add roles」とでで役職付与ができないですね... どうしてこんなに上手くいかないのか...
Go321123

2021/10/22 20:41

HerokuのApplication Logs をみてたらこんなものを発見しました ``` 2021-10-22T20:37:42.034084+00:00 heroku[discordbot.1]: Restarting 2021-10-22T20:37:42.132388+00:00 heroku[discordbot.1]: State changed from up to starting 2021-10-22T20:37:42.690668+00:00 heroku[discordbot.1]: Stopping all processes with SIGTERM 2021-10-22T20:37:43.014320+00:00 heroku[discordbot.1]: Process exited with status 0 2021-10-22T20:37:44.870312+00:00 heroku[discordbot.1]: Starting process with command `python discordbot.py` 2021-10-22T20:37:45.484170+00:00 heroku[discordbot.1]: State changed from starting to up 2021-10-22T20:37:48.580553+00:00 app[discordbot.1]: Ignoring exception in on_ready 2021-10-22T20:37:48.581017+00:00 app[discordbot.1]: Traceback (most recent call last): 2021-10-22T20:37:48.581045+00:00 app[discordbot.1]: File "/app/.heroku/python/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event 2021-10-22T20:37:48.581045+00:00 app[discordbot.1]: await coro(*args, **kwargs) 2021-10-22T20:37:48.581047+00:00 app[discordbot.1]: File "discordbot.py", line 27, in on_ready 2021-10-22T20:37:48.581047+00:00 app[discordbot.1]: role = guild.get_role(ROLE_ID) 2021-10-22T20:37:48.581063+00:00 app[discordbot.1]: AttributeError: 'NoneType' object has no attribute 'get_role' 2021-10-22T20:37:51.000000+00:00 app[api]: Build succeeded ```
fj68

2021/10/22 20:52

> オフラインになってしまう原因がわかりました! よかったです!まずは1歩前進ですね! guild.get_role()で「NoneType object〜」が出るということは上手くguildを取得できていないようですね。 GUILD_IDが間違っているか、botの権限が足りないかだと思うのですが…… GUILD_IDが間違っていないか確かめるため「guild = bot.get_guild(GUILD_ID)」を「guild = discord.utils.get(bot.guilds, name="サーバ名")」に書き換えて同じエラーが出るか試してみてください。 もしそれでも同じエラーが出るようならbotの権限を見直しましょう。 あと少しです、頑張ってください!
Go321123

2021/10/23 09:17

guild の部分を上記の通り書き換えたらエラーはなくなりました。 質問なのですが、GUILD_ID ってserver id の事ですか? GUILD_IDの取得方法はDiscordのサーバーのアイコンを右クリックしてIDをコピーをクリックすることで得れて、数字の羅列の様なものですよね? ROLE_IDも同様のものですよね?
Go321123

2021/10/23 09:19

上記の通り書き換えた時のHerokuのApplication Logs 2021-10-23T09:10:33.000000+00:00 app[api]: Build started by user [gmail名] 2021-10-23T09:10:58.084876+00:00 heroku[discordbot.1]: State changed from crashed to starting 2021-10-23T09:10:57.827000+00:00 app[api]: Deploy 8b6b8939 by user [gmail名] 2021-10-23T09:10:57.827000+00:00 app[api]: Release v132 created by user [gmail名] 2021-10-23T09:11:00.727860+00:00 heroku[discordbot.1]: Starting process with command `python discordbot.py` 2021-10-23T09:11:01.348262+00:00 heroku[discordbot.1]: State changed from starting to up 2021-10-23T09:11:07.000000+00:00 app[api]: Build succeeded
fj68

2021/10/23 09:39

> 質問なのですが、GUILD_ID ってserver id の事ですか? GUILD_IDの取得方法はDiscordのサーバーのアイコンを右クリックしてIDをコピーをクリックすることで得れて、数字の羅列の様なものですよね? ROLE_IDも同様のものですよね? そうです。discord.pyだとサーバーのことをGuildと言うみたいです。 エラーは無くなったみたいですが、いかがでしょう? まだfail to add rolesのようならやはり権限の問題だと思うのですが…… command_prefixが自分が試していた時の'/'のままだったことに気がつきました。 コードを修正しておきます、すいません
Go321123

2021/10/23 11:16 編集

回答に書いてある通り、権限の項目でAdministar 以外全てにチェックしてURLを作成してサーバーに導入してます。あと逆にAdministarにチェックを入れてURLを作成したり、何度も入れ直したりしました。 ROLE_ID は役職付与したいロールのIDですよね? BOTのロールIDではなく、
fj68

2021/10/23 11:20

> 回答に書いてある通り、権限の項目でAdministar 以外全てにチェックしてURLを作成してサーバーに導入してます。あと逆にAdministarにチェックを入れてURLを作成したり、何度も入れ直したりしました。 ありがとうございます。 > ROLE_ID は役職付与したいロールのIDですよね? BOTのロールIDではなく おっしゃるとおりです。 guildがstr型になるというのはどういうことなのか……? discord.GuildかNoneになるはずなんですが……困りましたね もしかしてなんですが、guildという変数にどこかで文字列を入れていたりしませんか? 考えられる原因がこのくらいでして……一応の確認です。 もし心当たりがなければ、以下のようにして確認してみてください。 guild = discord.utils.get(bot.guilds, name="サーバ名") print(guild, type(guild)) # guildとその型を表示してみる
fj68

2021/10/23 11:21

print()した結果はHerokuのLogに出てきます
Go321123

2021/10/23 11:32 編集

str になるところは ' guild = discord.utils.get(GUILD_ID)' と、違うものに変わっていいたのでstr型になってました、直してもさっきと同様にNonTypeのエラーでした。 後、質問にHeroku のConfig Vars の設定の画像を載せておきます
Go321123

2021/10/23 11:40

教えて貰った通り、 guild = discord.utils.get(bot.guilds, name="サーバ名") print(guild, type(guild)) # guildとその型を表示してみる のコードを加えて Heroku の Log をみたらこんな感じでした 2021-10-23T11:37:12.000000+00:00 app[api]: Build started by user [gmail名] 2021-10-23T11:37:34.910260+00:00 app[api]: Deploy ad80cf2e by user [gmail名] 2021-10-23T11:37:35.354131+00:00 heroku[discordbot.1]: Restarting 2021-10-23T11:37:35.474064+00:00 heroku[discordbot.1]: State changed from up to starting 2021-10-23T11:37:34.910260+00:00 app[api]: Release v148 created by user [gmail名] 2021-10-23T11:37:36.256706+00:00 heroku[discordbot.1]: Stopping all processes with SIGTERM 2021-10-23T11:37:36.671861+00:00 heroku[discordbot.1]: Process exited with status 0 2021-10-23T11:37:38.051182+00:00 heroku[discordbot.1]: Starting process with command `python discordbot.py` 2021-10-23T11:37:38.674734+00:00 heroku[discordbot.1]: State changed from starting to up 2021-10-23T11:37:41.542074+00:00 app[discordbot.1]: None <class 'NoneType'> 2021-10-23T11:37:44.000000+00:00 app[api]: Build succeeded
fj68

2021/10/23 11:48

Config Varsの画像、ありがとうございます。 もしかして、なんですが、GUILD_IDやROLE_IDをintにし忘れているからかも……と気が付きました。 回答のコードを編集しましたので、試してみてください。 凡ミス、すいません!
Go321123

2021/10/23 12:13 編集

やりました!!! やっとDMで役職付与出来ました! 二日も時間を取らせてしまい申し訳ないです... この回答は後でベストアンサーとして登録しておきます、長い間、私の質問にいろいろ答えてくれ、協力もしてくれて本当にありがとうございます!
fj68

2021/10/23 12:14

いえ、こちらこそ細かい見落としがありお時間を取らせてしまいました……すみませんでした。 私も知らないことがあったので、勉強になりました。ありがとうございます。 完成できたのはGo321123さんの忍耐強さ故です。大変嬉しく思います。 この後も頑張ってください!
Go321123

2021/10/24 16:17

加えてもう一つ答えてくれるとありがたいのですが DMで '?r' だけ送ると、 ``` Traceback (most recent call last): File "/app/.heroku/python/lib/python3.8/site-packages/discord/ext/commands/bot.py", line 939, in invoke await ctx.command.invoke(ctx) File "/app/.heroku/python/lib/python3.8/site-packages/discord/ext/commands/core.py", line 855, in invoke await self.prepare(ctx) File "/app/.heroku/python/lib/python3.8/site-packages/discord/ext/commands/core.py", line 789, in prepare await self._parse_arguments(ctx) File "/app/.heroku/python/lib/python3.8/site-packages/discord/ext/commands/core.py", line 697, in _parse_arguments transformed = await self.transform(ctx, param) File "/app/.heroku/python/lib/python3.8/site-packages/discord/ext/commands/core.py", line 542, in transform raise MissingRequiredArgument(param) discord.ext.commands.errors.MissingRequiredArgument: word is a required argument that is missing. ``` と、返答されてしまい、これを 「合言葉を間違えていますよ」と、BOTが返答するように変えたいのですが、やり方をご存知でしょうか? 自分で試行錯誤したのですがうまくいかなくて...
fj68

2021/10/24 23:59

回答に追記しました。 他の回答者の方からも回答がもらえますし、後に同じような問題で困って検索した人にとっても有用なので、次からは新しい質問として分けた方がよいかもしれません。 新しい質問の方に関連する質問としてこの質問へのリンクを貼るのとここのコメントにその質問のリンクを貼るようにすると更に良いでしょう。 少しづつ機能が拡充されていっているようで、嬉しく思います。 頑張ってください!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問