---
title: discord-reminderbotの設計
description: discord-reminderbotの設計について考えてみる
tags: Discord, discord.py
lang: ja-jp
GA: UA-175602723-1
---
# かんぺきな設計
## 方針
- 日時を指定してメッセージを登録
- リマインドしてくれる
- ~~DBは使わない~~(用意が面倒臭いから)
- そうおもっていたが、sqlite3を使うことにする(何も用意せず使えるし)
- ユーザをキーに検索したり、日付を元に検索したりしたいため。dictではちょっと辛そう
- 環境変数`IS_HEROKU`がTrueなら、Discordのチャンネルにファイルを添付して、そこに~~ギルドの~~リマインダー情報を貼り付ける
- 最後に実行されたギルドの所定のチャンネルに保管(チャンネルがなかったら**勝手に作る**
- ~~できれば人間が読める形式にしたいかも~~
- sqlite3のdbにする。よく考えなくても、人間がよめちゃダメでしょう(DLしてsqlite3で読めばわかるけど)
- せっかくなのでAESとやらで暗号化しよう
- 1分くらいの遅延は許してもらう
- メンションはできるようにする
- メンションがあったらそれを使う
- チャンネル指定も可能(未指定は実行したチャンネル)
- チャンネルメンションを使う
## コマンド
- `$remind 2021/02/11 14:00 野菜を買ってくる`
- こんな感じで登録できるようにする
## 動き(と思ったこと)
- 1分に1回、自分の保持しているremindオブジェクトをさらって通知する(Taskを使う)
- ステータス(未実施、実施済)
- ギルドはどこか?
- 誰が実行したか?
- コマンド`ls`のときに他ギルド・他人の情報を表示しない
- 処理長引かせないために、remindは時間で昇順ソートしておくべき
- remind.remind_datetime > nowになったらそこで処理を終了
- そう思ってたけど、sqlite3ならいいか。。。
- 通知したら以下の処理を実行
- ステータスを実施済に変更
- `repeat`を確認。'1'の場合、`repeat_interval`を確認し、次のremindを作成
- python-dateutil(とソレに入ってるrrule)を使う
- `repeat_interval`に登録できるもの
- XX分:`XXmi`
- XX時間: `XXh`
- X日: `Xd`
- X週: `Xw`
- Xヶ月: `Xm`
- X年: `Xy`
- 特殊
- 平日: `平日`
- 休日: `休日`
- 月初: `月初`
- 月末: `月末`
- 2文字の時のみ発動
- 曜日: `月水金`**等**
- それぞれをrruleの`byweekday`リストに詰めて、startが翌日、endが1週間後で最初のやつを使う
## sqlite3
- create table
```sql
create table if not exists reminder_table (
id integer primary key autoincrement,
remind_datetime datetime,
guild integer,
member integer,
channel integer,
remind_message text,
status text,
mention text,
repeat_flg text,
repeat_interval text,
created_at datetime,
updated_at datetime
)
```
- カラムの説明(わかりにくいところのみ)
- status
- Finished: リマインド済
- Past: 過去日のため実行しないもの(insertする時に入れる)
- Progress: リマインド未済
- Canceled: キャンセルされたもの
- mention
- これをそのまま使えばメンションできる形式で保管
- repeat_flg
- 0: 繰り返さない
- 1: 繰り返す
- repeat_interval
- 上で説明したいろいろ
## 問題(気になること)
- タイムゾーン(HerokuやRepl.itなどの海外サーバで動かした時に問題ないか?)
- なんとなく付けたらRepl.itでもローカルで動いた
- ただ、たまに処理がおかしい???時もあるような。。。
## 使う予定のリンク
- sqlite3について
- [sqlite3入門 | Python学習講座]( https://www.python.ambitious-engineer.com/archives/745)
- [sqlite3 --- SQLite データベースに対する DB-API 2.0 インタフェース — Python 3.9.2 ドキュメント]( https://docs.python.org/ja/3/library/sqlite3.html#using-shortcut-methods)
- [SQLiteで日付時刻を扱う際のポイント - Qiita]( https://qiita.com/TomK/items/132831ab45e2aba822a8#localtime-%E8%B6%85%E4%BE%BF%E5%88%A9)
- [日付と時刻を取得する(date関数, time関数, datetime関数, julianday関数, strftime関数) | SQLite入門]( https://www.dbonline.jp/sqlite/function/index6.html#section4)
- [Python:sqlite3【SQLite データベース】 - リファレンス メモ](https://cercopes-z.com/Python/stdlib-sqlite3-py.html)
- [SQLiteのsqlite_sequence (AUTOINCREMENT) の挙動 - キリウ君が読まないノート]( https://note.kiriukun.com/entry/20181223-working-with-sqlite-sequence)
- [PythonでSQLite3を扱ってみる(備忘録) - Qiita]( https://qiita.com/ForestSeo/items/90decce9c74242a06657#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E4%BD%9C%E3%82%8B)
## 動画配信してみて思ったこと
- 30分ごとに番組を作るのは面倒臭い
- プレミアム会員ではないと、延長はできない(それぞれで枠を取得する必要がある)
- 地味で面白くない放送に人はこない(動画のサムネイルってどうなっていんだろう?)
- **プレミアム会員ではなくとも**、本人はタイムシフト動画を閲覧できる
- ちょっとびっくり。ダウンロードはプレミアム会員のみ
- OBSでは配信と同時に録画ができるので、それでやっておけというスタンスか
- あまりに面倒臭かったのでYouTubeにした(3/14)
## 文章置き場
### ニコ生のあれ
discord.pyとdiscord-py-slash-commandを利用して、DIscord用のリマインダーBotを一から作ってみます!!!!
プログラミング放送です。前回までニコ生でやってましたが30分ごとに枠を取り直すのが煩雑でYouTubeに来ました。DiscordのBotにあったらおもしろいアイデアは随時募集中、Botを作ってみたい方の質問等あれば答えます(答えられるなら)
今回やりたいこと:・slashコマンドの実装、タスクで定期的に実行してみる
URL1: <https://hackmd.io/637kGsB3R0y2VgL7Nu5DrA?view>
URL2: <https://scrapbox.io/maaaruuu/discord-reminderbotの設計>
### あらすじ
### その1 2021/02/21 11:20-11:50
- setting.pyを作り、ログレベルとトークンを取得するようにした
- 公式チュートリアルのやつから、Cogを使う方法に変える方法が分からず困る
- 音声が途切れ途切れだった(OBSのノイズゲートのせい)
### その2 2021/02/21 12:30-13:00
- Qiitaの記事をコピペし、Cog対応版を動かそうとするが動かない
- Qiitaの記事をそのままコピペすると動いた
- 結局、 動かす時のclassを変更しないままだったため
- 音声が途切れ途切れ、かつ、棒読みちゃんが謎に残響してた(OBSのノイズゲートのせい)。次回で直した
### その3 2021/02/21 13:31-14:01
- Cogの作成に着手
- ついでに、なんとなくremind.pyを作り始めた
### その4 2021/2/22 22:36-23:06
- sqlite3を使うことにした。DBの初期化(テーブル作成)したところ
- リマインドを作成する処理を作ろうとしたところで時間切れ
### その5 2021/2/22 23:38-24:08
- リマインドをDBに登録(insert)する処理を記載中
- なんとなく動く気がするが、@hereや@everyoneの時、Botでどうするかわかっていない(他は[<@99999>]( https://discordpy.readthedocs.io/ja/latest/api.html#discord.Message.raw_mentions)で良い)
### その6 2021/02/28 23:03-23:33
- [slashコマンド(discord)](https://scrapbox.io/maaaruuu/slash%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89(discord))を知ったので是非使ってみたいと思ったので実装してみる
- うまくいかず。その理由は「slash = SlashCommand(bot, sync_commands=True)」が認識されていなかったため
- `def __init__(self, command_prefix, intents):`の中に`slash = SlashCommand(self, sync_commands=True)`を追加し、動いた
- `simole-reminderbot.py`でとてもシンプルな構成にして動くことを確認し、それが今回のやり方だとbotとはselfに当たると気づいて解決
- Pythonが普通にできる人は普通に解決できそうな気がする。。。
### その7 2021/03/14 22:00-23:30
- slashコマンドの続き
- taskで定期的に実行させる
### その8 2021/03/21 21:30-23:15
- listの@を無効化する
- 簡易的な日付入力を許可する
- 別チャンネルへ投稿できるようにする
- listコマンドの出力を少し整形
### その9 2021/3/22 22:42-0:42
- AES暗号化(3分クッキング形式にする予定)
- 環境変数`KEEP_DECRYPTED_FILE`がTRUEの時のみ、復号化されたDBを残す
- 繰り返しの対応(途中)
- 繰り返し間隔だけ延ばした次のリマンドが現実時間に追いつかない時、さらに次の間隔だけ延ばすようにした
- 一般的な、分〜年までの繰り返し間隔に対応(特殊なパターンについては対応していない)
- やりたいことが増えた(繰り返し回数の話、他コマンド)
### その10 2021/3/23 22:00-24:00
- 繰り返し回数を設定するオプション
- 繰り返し回数だけ繰り返されたら、repeat_flgが'0'になり、繰り返さない
- 繰り返された回数を表示しても良いかも(繰り返しの場合。`(2)とか末尾に`)
- 他のコマンドを作ってみる(対応できず)
- リマインドを削除するコマンド
- リマインドの繰り返しフラグを'0'にするコマンド
### その11 2021/3/29 22:55-24:00
- 特殊な繰り返し間隔について対応
- 対応済
- リマインドを削除するコマンド
### そのXX(まだやってない)
- 他のコマンドを作ってみる
- リマインドの繰り返しフラグを'0'にするコマンド
- メンバーあてのメンションがわかりづらい(ID)ので、時間があったら名前にする([guildのget_memberを使う!](https://discordpy.readthedocs.io/ja/latest/api.html#discord.Guild.get_member))
- Heroku対応
- HerokuはPaasの一種。Salesforceが運営(買収したらしい)。データが1日1回は初期化される
- モンキーテスト
- 本当ならテストもコメントとかに埋め込んでいい感じするなり、GitHubとかに上げてCIでなんやかんやすると思うが、そんな知識はない!のでやらない!!
- そのため、適当に動かしてバグっぽい挙動に気づくというお猿さんみたいなことをする