Discordメッセージ削除bot

## はじめに

Discordで過去の不要なメッセージを自動で一括削除したいと感じたため、Discordメッセージ削除botを作成しました。
（ほぼChatGPT製）

既に有名なAutoDeleteというボットがありますが、最近は更新が止まっており、試したところ安定して動作しなかったため、新しいボットを作成しました。このボットはサーバーで提供されるものではなく、各自のローカル端末などで実行する必要があります。

なお、このボットを設定・運用するには、ある程度のプログラミング言語の知識とLinuxの知識が必要です。これは、ボットをローカルで実行するためにサーバーを用意し、適切に設定する必要があるためです。

## コマンド一覧と使用方法

1. **`set_interval` コマンド**
    - **使用方法**: `!set_interval <minutes>`
    - **説明**: メッセージの削除チェック間隔を分単位で設定します。
    - **例**:
        - `!set_interval 1`: メッセージの削除チェック間隔を1分に設定。
        - `!set_interval 720`: メッセージの削除チェック間隔を12時間（720分）に設定。
2. **`set_cutoff_minutes` コマンド**
    - **使用方法**: `!set_cutoff_minutes <minutes>`
    - **説明**: 削除対象となるメッセージが何分前のものかを設定します。この時間を超える前のメッセージが削除対象となります。
    - **例**:
        - `!set_cutoff_minutes 1`: 1分前のメッセージを削除対象に設定。
        - `!set_cutoff_minutes 720`: 12時間（720分）前のメッセージを削除対象に設定。
3. **`delete_messages_before` コマンド**
    - **使用方法**: `!delete_messages_before <channel_id> <minutes>`
    - **説明**: 指定したチャンネルIDのチャンネルで、指定した時間（分単位）以上前の全てのメッセージを削除します。
    - **例**:
        - `!delete_messages_before 123456789012345678 1`: チャンネルID `123456789012345678` 内で1分以上前の全てのメッセージを削除。
        - `!delete_messages_before 123456789012345678 10`: チャンネルID `123456789012345678` 内で10分以上前の全てのメッセージを削除。

---

## ボットの作成と設定手順

### 1. Discordボットの作成

1. Discord Developer Portal にアクセスし、ログインします。
2. 左のメニューから「Applications」を選択し、「New Application」をクリックして新しいアプリケーションを作成します。
3. ボットの名前を入力し、「Create」をクリックします。
4. 左のメニューから「Bot」を選択し、「Add Bot」をクリックしてボットを追加します。
5. ボットのトークンを「Click to Reveal Token」で表示し、コピーしておきます。このトークンは後で使用します。

### 2. トークンの払い出しと管理

1. ボットのトークンは、ボットの認証に使用されます。これは機密情報であり、他人と共有しないように注意してください。
2. トークンを紛失した場合やセキュリティ上の理由で変更したい場合は、「Regenerate」ボタンを使用して新しいトークンを生成できます。

### 3. OAuth2と権限の設定

1. 左のメニューから「OAuth2」を選択します。
2. 「OAuth2 URL Generator」に移動し、以下の設定を行います：
    - **SCOPES**: `bot` を選択します。
    - **BOT PERMISSIONS**: ボットに必要な権限を設定します。メッセージの削除が必要な場合、以下の権限を選択します：
        - `Manage Messages`（メッセージの管理）
        - `Read Message History`（メッセージ履歴の読み取り）
3. ページの下部にある「Generated URL」で表示されるURLが、ボットをサーバーに招待するためのリンクです。このリンクを使用して、ボットを追加したいサーバーに招待します。

### 4. .envファイルの作成

1. プロジェクトのルートディレクトリに `.env` ファイルを作成します。
2. `.env` ファイルに以下の内容を記述し、先ほどコピーしたトークンを設定します。

```makefile
DISCORD_TOKEN=your_discord_bot_token_here
```

`your_discord_bot_token_here` は取得したトークンに置き換えてください。

### 5. Pythonコードの作成と設定

1. 必要なライブラリをインストールします：
    
    ```
    pip install discord.py python-dotenv pytz
    ```
    
2. Pythonファイル（例：`bot.py`）に上記のコードを記述します。
    
    ```python
    import discord
    from discord.ext import commands, tasks
    import os
    from dotenv import load_dotenv
    from datetime import datetime, timedelta
    from pytz import timezone
    
    # .envファイルから環境変数をロード
    load_dotenv()
    TOKEN = os.getenv('DISCORD_TOKEN')
    
    intents = discord.Intents.default()
    intents.messages = True
    intents.message_content = True
    
    bot = commands.Bot(command_prefix="!", intents=intents)
    
    delete_interval = 60  # デフォルトで1時間（60分）おきにチェック
    delete_cutoff_minutes = 720  # デフォルトで12時間前のメッセージを削除対象
    
    # JSTのタイムゾーンを定義
    JST = timezone('Asia/Tokyo')
    
    @bot.event
    async def on_ready():
        print(f'Logged in as {bot.user.name}')
        check_old_messages.start()
    
    @tasks.loop(minutes=delete_interval)
    async def check_old_messages():
        print(f"Checking messages at {datetime.utcnow()} UTC")
        now = datetime.utcnow().replace(tzinfo=timezone('UTC')).astimezone(JST)
        cutoff = now - timedelta(minutes=delete_cutoff_minutes)
    
        for guild in bot.guilds:
            for channel in guild.text_channels:
                try:
                    messages = []
                    async for message in channel.history(before=cutoff):
                        messages.append(message)
                    print(f"Found {len(messages)} messages to delete at {channel.name}.")
                    for message in messages:
                        print(f"Attempting to delete message from {message.author}: {message.content}")
                        await message.delete()
                        print(f"Deleted message from {message.author}: {message.content}")
                except discord.Forbidden:
                    print(f"Can't delete messages in {channel.name} due to lack of permissions.")
                except discord.HTTPException as e:
                    print(f"Failed to delete message in {channel.name}: {e}")
    
    @bot.command()
    async def set_interval(ctx, minutes: int):
        """メッセージの削除間隔を設定します。"""
        global delete_interval
        delete_interval = minutes
        if check_old_messages.is_running():
            check_old_messages.change_interval(minutes=delete_interval)
            await ctx.send(f"メッセージの削除間隔を {minutes} 分に変更しました。")
        else:
            check_old_messages.change_interval(minutes=delete_interval)
            check_old_messages.start()
            await ctx.send(f"メッセージの削除間隔を {minutes} 分に設定しました。")
    
    @bot.command()
    async def set_cutoff_minutes(ctx, minutes: int):
        """削除対象のメッセージが何分前のものか設定します。"""
        global delete_cutoff_minutes
        delete_cutoff_minutes = minutes
        await ctx.send(f"削除対象を {delete_cutoff_minutes} 分以上前のメッセージに設定しました。")
    
    @bot.command()
    async def delete_messages_before(ctx, channel_id: int, minutes: int):
        """指定したチャンネルで特定の時間前のメッセージを削除します。"""
        channel = bot.get_channel(channel_id)
        if channel:
            now = datetime.utcnow().replace(tzinfo=timezone('UTC')).astimezone(JST)
            cutoff = now - timedelta(minutes=minutes)
            try:
                messages = []
                async for message in channel.history(before=cutoff):
                    messages.append(message)
                print(f"Retrieved {len(messages)} messages for deletion.")
                if messages:
                    for message in messages:
                        print(f"Deleting message from {message.author}: {message.content}")
                        await message.delete()
                    await ctx.send(f"{len(messages)} 件のメッセージを削除しました。")
                else:
                    await ctx.send("削除対象のメッセージがありません。")
            except discord.Forbidden:
                await ctx.send(f"メッセージを削除する権限がありません。")
            except discord.HTTPException as e:
                await ctx.send(f"メッセージの削除に失敗しました: {e}")
    
    bot.run(TOKEN)
    
    ```
    

### 6. ボットの実行

1. ターミナルでPythonファイルがあるディレクトリに移動します。
2. 次のコマンドを実行してボットを起動します：
    
    ```
    python bot.py
    ```
    

ボットが正常に起動すると、指定したDiscordサーバーでメッセージの削除などのコマンドが使用できるようになります。

### 注意点

- ボットを停止して再起動した場合、設定はデフォルトに戻ります。再設定が必要な場合は、コマンドを再度実行してください。
- トークンは非常に機密性が高く、漏洩しないように注意してください。