This commit is contained in:
115
Discord Backup Bot/README.md
Normal file
115
Discord Backup Bot/README.md
Normal file
@@ -0,0 +1,115 @@
|
||||
# Discord Backup Bot
|
||||
|
||||
Archives a single Discord server's text channels in full fidelity: messages, attachments, embeds, reactions, reply/thread structure, edits, and deletions. Stores everything in a local SQLite database with attachment files on disk. Resumes cleanly after crashes or restarts.
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Create a Discord bot
|
||||
|
||||
1. Open <https://discord.com/developers/applications> and create a new application.
|
||||
2. Under **Bot**, click **Reset Token** and copy the token somewhere safe.
|
||||
3. Under **Privileged Gateway Intents**, enable:
|
||||
- **Message Content Intent** (required)
|
||||
4. Under **OAuth2 → URL Generator**:
|
||||
- Scopes: `bot`
|
||||
- Bot Permissions: `View Channels`, `Read Message History`
|
||||
5. Open the generated URL and add the bot to your server.
|
||||
|
||||
### 2. Get the IDs
|
||||
|
||||
Enable Developer Mode in Discord: **User Settings → Advanced → Developer Mode**.
|
||||
|
||||
Right-click your server icon → **Copy Server ID** (this is `guildId`).
|
||||
Right-click each channel you want backed up → **Copy Channel ID**.
|
||||
|
||||
### 3. Install and configure
|
||||
|
||||
Requires Node.js 22.5 or newer (uses the built-in `node:sqlite` module — no native compilation).
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Copy `config.example.json` to `config.json` and fill in:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "your bot token",
|
||||
"guildId": "your server id",
|
||||
"channelIds": ["channel id 1", "channel id 2"],
|
||||
"dataDir": "./data",
|
||||
"attachmentConcurrency": 3
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Run
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
The bot will log in, attach its live listener, start downloading attachments in the background, and backfill each configured channel (walking backward through old messages and forward to catch anything missed during downtime). Leave it running 24/7. Stop with Ctrl+C — next start resumes from the last checkpoint.
|
||||
|
||||
## What gets captured
|
||||
|
||||
- Messages (content, author, timestamps, reply target)
|
||||
- Edits — full edit history from when the bot is present
|
||||
- Deletions — soft-delete flag with timestamp
|
||||
- Attachments — downloaded to `data/attachments/<channel_id>/<message_id>/<filename>`
|
||||
- Embeds — link previews, bot embeds (stored as JSON)
|
||||
- Reactions — per user, with add/remove timestamps
|
||||
- Threads — active and public archived; new threads via live events
|
||||
- Author info — username, display name, avatar URL snapshot
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Pre-bot edits and deletions are unrecoverable.** Discord's API does not expose edit/deletion history — the bot only sees them live.
|
||||
- **Reactions removed before the bot joined are lost.** Reactions still present at backfill time are captured.
|
||||
- **Private archived threads** are not backfilled (requires extra permissions). Private threads created while the bot is live are captured.
|
||||
- **Signed attachment URLs expire after ~24 hours.** If the bot is offline that long after a message is posted, its attachment URL may 403/410 before the downloader can fetch it — metadata is preserved but the file is unrecoverable.
|
||||
- **Gateway reconnects that don't trigger a fresh `ready`** don't re-run backfill. Restart the bot to catch up after long disconnects.
|
||||
|
||||
## Storage
|
||||
|
||||
```
|
||||
data/
|
||||
├── backup.db # SQLite (WAL mode; -shm / -wal files appear while running)
|
||||
└── attachments/
|
||||
└── <channel_id>/<message_id>/<attachment_id>/<filename>
|
||||
```
|
||||
|
||||
## Inspecting the archive
|
||||
|
||||
```bash
|
||||
sqlite3 data/backup.db
|
||||
```
|
||||
|
||||
Useful queries:
|
||||
|
||||
```sql
|
||||
-- Messages per channel (including threads)
|
||||
SELECT c.name, COUNT(*) AS count
|
||||
FROM messages m JOIN channels c ON c.id = m.channel_id
|
||||
GROUP BY c.id ORDER BY count DESC;
|
||||
|
||||
-- Backfill progress
|
||||
SELECT name, is_thread, backfill_complete,
|
||||
oldest_fetched_id, newest_fetched_id
|
||||
FROM channels;
|
||||
|
||||
-- Pending / failed attachments
|
||||
SELECT
|
||||
SUM(CASE WHEN downloaded = 1 THEN 1 ELSE 0 END) AS done,
|
||||
SUM(CASE WHEN downloaded = 0 AND download_failed = 0 THEN 1 ELSE 0 END) AS pending,
|
||||
SUM(download_failed) AS failed
|
||||
FROM attachments;
|
||||
|
||||
-- Messages with edit history
|
||||
SELECT m.id, m.content, COUNT(e.message_id) AS edits
|
||||
FROM messages m LEFT JOIN message_edits e ON e.message_id = m.id
|
||||
GROUP BY m.id HAVING edits > 0;
|
||||
|
||||
-- Deleted messages
|
||||
SELECT id, author_id, content, deleted_at FROM messages
|
||||
WHERE deleted_at IS NOT NULL ORDER BY deleted_at DESC LIMIT 20;
|
||||
```
|
||||
Reference in New Issue
Block a user