Documentation Index
Fetch the complete documentation index at: https://mintlify.com/trustlessmatt/discord-exporter-bot/llms.txt
Use this file to discover all available pages before exploring further.
Functions for exporting Discord messages, serializing message data, and calculating export statistics.
export_channel_messages()
async def export_channel_messages(
channel,
hours: int,
config: Config
) -> list:
"""Export messages from a channel within the last X hours."""
import discord
from bot import export_channel_messages, Config
config = Config.from_env()
channel = guild.get_channel(channel_id)
# Export last 24 hours of messages
messages = await export_channel_messages(channel, 24, config)
print(f"Exported {len(messages)} messages")
for msg in messages:
print(f"{msg['author']['name']}: {msg['content_clean']}")
Exports all messages from a specific Discord channel within the specified time range.
Parameters
channel
discord.TextChannel
required
Discord text channel object to export messages from.
Number of hours to look back from current time. Messages older than this are excluded.
Bot configuration object containing timezone and other settings.
Returns
List of serialized message dictionaries. Empty list if channel is inaccessible or on error.
Message Dictionary Structure:
See serialize_message() for complete message structure.
Behavior
- Uses
channel.history() with after parameter for efficient filtering
- Automatically handles pagination for channels with many messages
- Returns empty list on permission errors (logs warning)
- Returns empty list on other errors (logs error)
- Converts all timestamps to configured timezone
This function handles Discord API rate limits automatically through discord.py’s built-in rate limiter.
async def perform_export(
bot: commands.Bot,
config: Config,
hours: int
) -> Optional[dict]:
"""Perform the export operation across all channels concurrently."""
from discord.ext import commands
from bot import perform_export, Config
bot = commands.Bot(command_prefix="!", intents=intents)
config = Config.from_env()
# Export last 48 hours from all channels
result = await perform_export(bot, config, 48)
if result:
print(f"Exported {result['total_messages']} messages")
print(f"Saved to: {result['filename']}")
print(f"Active channels: {result['channel_count']}")
else:
print("Export failed")
Performs a complete export across all text channels in the configured guild, saves to JSON file, and returns statistics.
Parameters
Discord bot instance with active connection.
Bot configuration containing guild_id, exports_dir, and timezone settings.
Time range in hours to export messages from.
Returns
Export result dictionary with statistics and data, or None if export failed.
Success Response Structure:
{
"filename": "exports/discord_export_20260304_120000_ET.json",
"total_messages": 1547,
"channel_count": 8,
"export_data": {
"guild_name": "My Server",
"export_time_eastern": "2026-03-04T12:00:00-05:00",
"export_time_utc": "2026-03-04T17:00:00+00:00",
"timezone": "America/New_York (Eastern Time - auto DST)",
"time_range_hours": 24,
"channels": {
"general": {
"channel_id": "1234567890",
"messages": [...]
}
}
},
"stats": {
"total_messages": 1547,
"active_channels": 8,
"contributors": {"user1", "user2"},
"contributor_count": 15
}
}
Behavior
- Exports from all text channels concurrently using
asyncio.gather()
- Creates
exports directory if it doesn’t exist
- Generates timestamped JSON filename with Eastern Time
- Only includes channels with messages in the time range
- Returns
None if guild not found or save fails
Use concurrent export for better performance. The function processes all channels in parallel rather than sequentially.
serialize_message()
def serialize_message(
message,
guild,
config: Config
) -> dict:
"""Convert a Discord message to a serializable dictionary."""
from bot import serialize_message, Config
config = Config.from_env()
# Serialize a single message
message_dict = serialize_message(message, guild, config)
print(f"Message ID: {message_dict['message_id']}")
print(f"Author: {message_dict['author']['display_name']}")
print(f"Content: {message_dict['content_clean']}")
print(f"Timestamp: {message_dict['timestamp']}")
Converts a Discord message object into a JSON-serializable dictionary with cleaned content and metadata.
Parameters
Discord message object to serialize.
Guild object for resolving mentions to readable names.
Configuration containing timezone settings for timestamp conversion.
Returns
Serialized message dictionary with all metadata and cleaned content.
Message Dictionary Structure:
{
"message_id": "1234567890123456789",
"author": {
"name": "username",
"display_name": "Display Name",
"id": "9876543210987654321",
"bot": False
},
"content": "Hey <@123456> check <#789012>", # Raw content
"content_clean": "Hey @username check #general", # Cleaned mentions
"timestamp": "2026-03-04T12:34:56-05:00", # Eastern Time
"timestamp_utc": "2026-03-04T17:34:56+00:00",
"edited_timestamp": "2026-03-04T12:35:00-05:00", # or None
"attachments": [
{
"filename": "image.png",
"url": "https://cdn.discord.com/...",
"size": 245678
}
],
"embeds": 2, # Count of embeds
"reactions": [
{"emoji": "👍", "count": 5},
{"emoji": "❤️", "count": 3}
],
"mentions": [
{"id": "123456", "name": "username", "display_name": "Display Name"}
],
"channel_mentions": [
{"id": "789012", "name": "general"}
],
"thread": "Thread Name" # or None
}
Content Cleaning
The function converts Discord mentions from internal format to readable names:
<@123456> → @username
<#789012> → #channel-name
<@&456789> → @role-name
If a mentioned user, channel, or role no longer exists, the original mention format is preserved.
calculate_export_stats()
def calculate_export_stats(export_data: dict) -> dict:
"""Calculate statistics from export data."""
from bot import calculate_export_stats
# After performing export
result = await perform_export(bot, config, 24)
export_data = result["export_data"]
stats = calculate_export_stats(export_data)
print(f"Total messages: {stats['total_messages']}")
print(f"Active channels: {stats['active_channels']}")
print(f"Contributors: {stats['contributor_count']}")
print(f"Contributors list: {stats['contributors']}")
Calculates summary statistics from export data including message counts, active channels, and unique contributors.
Parameters
Export data dictionary containing channels and messages. Must have structure from perform_export().
Returns
Statistics dictionary with message counts and contributor information.
Statistics Structure:
{
"total_messages": 1547, # Total message count across all channels
"active_channels": 8, # Number of channels with messages
"contributors": { # Set of unique display names (excludes bots)
"Alice",
"Bob",
"Charlie"
},
"contributor_count": 15 # Number of unique human contributors
}
Behavior
- Counts all messages across all channels
- Only counts channels that have at least one message
- Excludes bot messages from contributor calculation
- Uses display names for contributor identification
- Returns set for
contributors to ensure uniqueness
Bot messages (where author.bot is True) are excluded from contributor statistics but included in total message count.
Integration Example
Complete workflow using all export functions:
from discord.ext import commands
from bot import Config, perform_export, calculate_export_stats
import json
# Initialize
config = Config.from_env()
bot = commands.Bot(command_prefix="!", intents=intents)
@bot.command()
async def export(ctx, hours: int = 24):
"""Export command handler"""
# Perform full export
result = await perform_export(bot, config, hours)
if not result:
await ctx.send("Export failed!")
return
# Access the data
export_data = result["export_data"]
stats = result["stats"]
# Report results
await ctx.send(
f"Exported {stats['total_messages']} messages\n"
f"From {stats['active_channels']} channels\n"
f"By {stats['contributor_count']} contributors\n"
f"Saved to: {result['filename']}"
)
# Load the saved file
with open(result['filename'], 'r') as f:
saved_data = json.load(f)
# Process channels
for channel_name, channel_data in saved_data['channels'].items():
message_count = len(channel_data['messages'])
print(f"#{channel_name}: {message_count} messages")