つれづれなるままに日々の色々なことを綴ります

【Discord Bot】DISCORD_TOKENを間違ってGithubに上げてしまった

はじめに

せこせことDiscord Botを作っています。先日、間違えてDISCORD_TOKENをGithubに上げるという大罪を犯しました。(リセット&再生成済み) 戒めと同じような過ちを犯すかもしれない誰かのために記事をしたためておきます…。

(本当に反省しています…。筆者はプログラミング初心者につき、間違いあったらコメント等お願いします)

起きたこと

コード内にTOKENを記載したままGithubにプッシュした。

どうなったか

  • Discordのシステムに速攻で怒られた。
  • ビビるぐらいすぐに通知が来た。システムが優秀で、システム側ですぐにリセットをかけてくれたらしく大事には至らなかった。
    ありがとう安全Jim

すべきこと

(真っ先にすべき)DiscordのDeveloper Portalで該当BotのTOKENのリセット、再発行

上述の通り、システム側がリセットをかけてくれている場合もありますが、念のため、自分でDeveloper Portalにアクセスし、TOKENがリセットされているか確認してください…。

リモートリポジトリからpushの存在を消し飛ばす

git resetコマンドでどうにか。

qiita.com

対策

環境変数内にTOKENを記載しておく

最初からこうしておけば何ら問題なかった…。めんどくさがってローカルで実行確認する際にTOKENを記載したのが悪いです。 あとLinuxへの苦手意識が…。

おわりに

夜中に突然相談して、解決を手伝ってくれたフレンドに感謝…

【Discord.py】TypeError: __init__() missing 1 required keyword-only argument: 'intents'というエラーが出る

はじめに

Discord botの改修作業をしていると、intents周りのエラーが出ました。直したのでメモを残しておきます。

プログラミング初心者につき、何か間違いあったらコメントお願いいたします。

開発環境

  • discord.py 2.1.0
  • python3 3.8.10

起きたこと

Botを実行すると以下のようなエラーが出た

Traceback (most recent call last):
  File "main.py", line 12, in <module>
    client = discord.Client()
TypeError: __init__() missing 1 required keyword-only argument: 'intents'

解決方法

とくに拘りがない場合

client = discord.Client()

client = discord.Client(intents=discord.Intents.all())

に書き換える

一体何だったのか

Discord.pyのアップデートにより、intentsが必須になったようです。 公式ドキュメントでは以下のように例が示されています。

# before 
client = discord.Client()

# after 
intents = discord.Intents.default()
client = discord.Client(intents=intents)

そもそもintentsとは何なのか

ドキュメントには以下のように記載があります。

バージョン1.5では Intents が導入されました。これにより、Botの書き方が根本的に変わります。基本的にインテントは、特定のイベント群をBotに サブスクライブさせるためのものです。各インテントに対応するイベントは、 Intents のドキュメントに個別の属性として記載されています。

インテントは intents 引数を介して Client またはそのサブクラス(AutoShardedClient, AutoShardedBot, Bot)のコンストラクタに渡されます。

当方、猿以下なので、あんまり理解が及びませんでしたが・・・

zenn.dev

intentを指定しないことは、つまりそれに関するイベントを一切受信しなくなるようです。 標準的なインテントに関しては、デフォルトで渡すことができ、追加の許可や設定を必要としません。しかし、一部の特権的なintentsは、まずDiscord のDeveloper portal内で設定を必要とします。 (逆にいうと、個人開発レベルの小規模なBotであれば、とりあえず設定をオンにしておいて、すべてのintentsを許可にしておけばそうそう詰まることはなさそうです)

何のintentsが何のイベントに関連ついてるかわからないよ~!

インターネッツをさまよっていたら、「Discord Intents Calculator」なるサイトを見つけました。 右側のIntentsにチェックを入れると、何のイベントにアクセスできるか教えてくれます。

ディスコードインテンツ計算機

discord-intents-calculator.vercel.app

一応、公式ドキュメントからも参照できます。

まとめ

参考文献

teratail.com

discord.com

【Discord.py】RuntimeError: no running event loopというエラーが出て、tasks.loopが実行できない

はじめに

制作しているDiscord Botの改修作業を行っている途中で、loop周りのエラーにぶち当たりました。解決に少々時間を要したので、メモを残しておきます。

開発環境

  • discord.py 2.1.0
  • python3 3.8.10

起きたこと

Discord Botを実行すると以下のエラー文が出るようになった。

Traceback (most recent call last):
  File "main.py", line 50, in <module>
    loop.start()
  File "/home/oimo/.local/lib/python3.8/site-packages/discord/ext/tasks/__init__.py", line 398, in start
    self._task = asyncio.create_task(self._loop(*args, **kwargs))
  File "/usr/lib/python3.8/asyncio/tasks.py", line 381, in create_task
    loop = events.get_running_loop()
RuntimeError: no running event loop
sys:1: RuntimeWarning: coroutine 'Loop._loop' was never awaited

解決策

  • loopの起動をon_readyの中に仕込む
import discord
from discord.ext import tasks

# この中にloop.startを仕込む
@client.event
async def on_ready():
    loop.start()

@tasks.loop(seconds=60)
async def loop():
    now = datetime.now(timezone('Asia/Tokyo')).strftime('%H:%M')
    if now.hour == 19 and now.minute == 30:
        channel = client.get_channel(CHANNEL_ID)
        await channel.send('ゴミ出しに行こうね!')  

一体なんだったのか

Discord.py 2.0.0/python 3.1以上の環境で、「discord.ext.tasks」を使用しているときに起きるようです。

もともと「discord.ext.tasks」を使うと、asyncioという並行処理のコードを書くためのライブラリを使用せずとも、ループを実行させられるらしい。しかし、Discord.py側のアップデートか何なのかbotの起動前に、ただ単にループ処理実行を書くだけでは上手く起動しないようになっています。

そこで、上記のようにon_readyにループ実行を入れてあげれば動くらしい。

# うまく動作しないパターン
@client.event
async def on_ready():

@tasks.loop(seconds=60)
async def loop():
    now = datetime.now(timezone('Asia/Tokyo')).strftime('%H:%M')
    if now.hour == 19 and now.minute == 30:
        channel = client.get_channel(CHANNEL_ID)
        await channel.send('ゴミ出しに行こうね!')  

loop.start()

まとめ

timezone周りを修正したかっただけなのに、これが出てきてえらい大変困りました。

参考文献

teratail.com

【Discord.py】タイムゾーンを考慮して、指定した時間にBotに発言してもらう

はじめに

Discord.py を使用して、Discord Botを制作しています。 以前、「指定した時間にBotにメッセージを送信してもらう」という機能を制作しましたが、Railwayにてデプロイした際、日本時間ではなくサーバーのローカルの時間で送信が実行されてしまうということがおきました。 それを修正していきたいと思います。 なお、プログラミング初心者につき、間違いありましたらコメントにお知らせください…。

開発環境

  • discord.py 2.1.0
  • python3 3.8.10

やりたいこと

  • タイムゾーンを考慮しつつ、指定した時間にBotにメッセージを発言してもらう

やったこと

pytzの導入

Pythonにてタイムゾーンを利用するときに便利なライブラリ「pypz」を導入しました。

インストールは以下より。

$ pip install pytz

日付の取得時にタイムゾーンを取得する

datetime.nowで日付等を指定するときにタイムゾーンを指定します。

now = datetime.now(timezone('Asia/Tokyo'))

時間でメッセージを送信するようにする

上記で修正した分を含めて、メッセージを送信するようになおしていきます。

import discord
from discord.ext import tasks
from datetime import datetime
from pytz import timezone

# 毎日19時半にゴミ出しを促すメッセージを送信する
@tasks.loop(seconds=60)
async def loop():
    # 現在の時刻
    now = datetime.now(timezone('Asia/Tokyo'))
    if now.hour == 19 and now.minute == 30: 
        channel = client.get_channel(CHANNEL_ID)
        await channel.send('ゴミ出しに行こうね!')  

おわり

時差のことをすっかり忘れていて、19時半に設定したメッセージがしばらく朝の4時半にずっと届いてました。

【Discord.py】Railwayのテンプレを改造して初心者でも楽にDiscord botを常時稼働させる

はじめに

discord.pyを使用して、Discord botを制作しています。 今回、botをRailwayに投げ込み常時稼働させて見たいと思います。 なお、執筆者は大変プログラミング初心者です。 何か間違ってたら教えてください。

あらかじめ必要なもの

  • きちんと動作しているDiscord.pyのファイル
  • Githubのアカウント

この記事に向いている人

  • ネット記事を見ながら見よう見まねで作ったbotを常時稼働させて見たい人
  • デプロイとか何すればいいかよくわからない人

Railwayに会員登録する

公式サイトにアクセスして会員登録しましょう。 Githubと連携させて登録します。

Railway公式のDiscordbotテンプレートプロジェクトを自分のGithubに持ってくる

RailwayのDiscord botテンプレートページにアクセスします。

Repository details

自分のGithubアカウントが認識されているか確認して見てください。 プライベートリポジトリにしたい場合はチェックを入れます。

Environment variables

「DISCORD_TOKEN」を記入します。TOKENはDiscordのdeveloperページから確認できます。

上記2つを記入したら右下の「Deploy」ボタンをクリックします。

main.pyの中身を制作していたDiscord botファイルで書き換える

2がうまくいっていたら、Githubにレポジトリが1つ増えているはずです。

該当レポジトリを開き、「main.py」に、あらかじめ制作していたDiscord botファイルをコピペしましょう。 もし元々のファイルにTOKENをそのまま記載していたら消し去っておき、環境変数から呼び出すようにしておこう。。。(n敗)

client.run(os.environ["DISCORD_TOKEN"])

また、デフォルトでmain.pyが起動するよう、Railway側で設定されているようなので、特にこだわりがなければmain.pyの名前のままがいいと思います。

必要に応じて「requirements.txt」の中身を書き換える

もし特別なパッケージを使っている場合は、この中身も増やしておかないと後々エラーを吐きます。

Railwayに戻りDeployする

Githubに変更をコミットすれば、自動でRedeployが走ります。もし真っ赤っかな表示になって失敗している時は「Build logs」や「Deploy logs」を見て原因を探って見てください。

オンライン表示になってDeploy成功!

オンラインになった時の起動メッセージが送信されています。これで常時稼働させられるようになりました。

おわりに

デプロイするために必要なファイルとか全く知らなかったので、テンプレをそのまま流用することで比較的楽に常時稼働に辿り着けました。(それでもTOKEN周りで一度詰まってますが・・・)

なお、Railwayは無料プランに制限があるので、どうすればいいかまだまだ検討中です。

参考記事

zenn.dev

zenn.dev

ikayome.hateblo.jp

と 相談に乗ってくれた有識者友人

サーバーとか知らないのにXHRとか使おうとするな

JavaScriptの練習がてら、ブラウザで動く漢字クイズアプリを制作中。

よく知らないものを浅はかに使おうとしたら浅はかに躓いたので戒め。

 

jsonを使っているクイズ作成サイトを参考にコードを書き出す。

1敗。この時点でjsonとか知らないので、大人しく引き返しておくべきだった。

ただ、jsのなかにクイズの問題を羅列するコードが綺麗に見えなくて、

参考にしたサイトは、問題文がjsonで独立していてかっこよく見えた。

jsonでググったら、なんか難しくなさそうだし、丸コピで行けるだろうと見切り発車。

 

当然コピペなので、コードの意味はわからないけど、なんかエラーを吐いているということは分かる。

まずここで、サンプルコードにあるXHRとはなんぞやとググる

どうやらjsonの取得にこのXMLHttpRequestというものを使っているらしい。

そしてサンプルコードに

let hogehoge = ' URL ' 

が無いことに気づく。ここでようやく、これはサーバーからjsonを取得しようとしているのだと気づく。(というよりマニュアルにそう書いてある、2敗)

バカなので、バカなりに考えてURLいろいろ試してみるけど、どうやら弾かれる。

developer.mozilla.org

ChromeのコンソールのCORSエラーという文字を初めてちゃんと認識する。

なんやそのエラー。知らん。ググる

クロスオリジンリソース共有 (CORS) エラーは、サーバーが CORS 標準で要求される HTTP ヘッダーを返さない場合に発生します。 API Gateway REST API または HTTP API からの CORS エラーを解決するには、CORS 標準を満たすように API を再構成する必要があります。

バカなので、分からない。

エラー文を見てみると、「Access-Control-Allow-Origin」を追加しろと書いてあるように読める。

思い出されるWordPressを構築したときの記憶。もしかして、なんか、ああいう、サーバー側に書かないといけないやつ…?????

 

json サーバー」でググる(安直)

GASとかAWSとか出てきて若干頭が無くなる。

その中で以下の記事を見つける。

www.agent-grow.com

自分で好きな内容を返せるようにしたい!
すでに用意されている内容だけでは物足りませんか?
自分で用意したデータを返してきてほしいですか?

そんなわがままなお気持ちがあっても大丈夫です!

先ほどの JSONPlaceholder で使用しているサーバーを、簡易的につかうことができます!

https://my-json-server.typicode.com/

これでは??

超特急でdb.jsonを作り、試してみる。

出てきた!!!!!

URLをコピペして、jsの該当箇所に貼り付けて保存。恐る恐る更新してみると…

エラー消えてる!!!!!!!!!!やったー!!!!!

全然解決じゃないかもだけど、とりあえあず勉強にはなった。

ちゃんとした解決策を勉強しないといけなさそう

さすがにこれは一時しのぎ。

というか、別にこんなまどろっこしいことしなくても良かったのでは?