14.7.3. Demo: Display Real Discord Comments and Replies#
Choose Social Media Platform: Reddit | Discord | Bluesky | No Coding
Now lets do the same thing we did on the last page (using recursion to display comments and replies), but do it on Discord! (Either for real or faked with the fake_praw library).
Note: Discord has different mechanisms to officially indicate “replies.” They can either be a new post that is in reply to a previous post, or they can be part of a thread. Additionally, in discord, simply posting after a previous post can informally indicate a reply, but it is hard to automatically deduce what is a reply in this way.
For the purposes of this example, we will only be using posts that are directly “replies” to previous posts. We will ignore threads in this demo.
Discord Setup#
# Load some code called "discord" that will help us work with Discord
import discord
# Load another library that helps the bot work in Jupyter Noteboook
import nest_asyncio
nest_asyncio.apply()
(optional) make a fake Discord connection with the fake_discord library
For testing purposes, we’ve added this line of code, which loads a fake version of discord, so it wont actually connect to Discord. If you want to try to actually connect to Discord, don’t run this line of code.
%run ../../fake_apis/fake_discord.ipynb
# Set up your Discord connection
# TODO: put the discord token for your bot below
discord_token = "m#5@_fake_discord_token_$%Ds"
# set up Discord client with permissions to read message_contents
intents = discord.Intents.default()
intents.message_content = True
Helper function to display text in an indented box#
(You don’t need to worry about how this works. This is that function that helps display posts in indented boxes)
from IPython.display import HTML, Image, display
import html
def display_indented(text, left_margin=0):
display(
HTML(
"<pre style='border:solid 1px;padding:3px;margin-left:"+ str(left_margin) + "px'>" +
html.escape(text) +
"</pre>"
)
)
Helper function to reconstruct reply tree#
(You don’t need to worry about how this works. This is that function that helps take the list of posts from the channel history and organize it into a proper reply tree structure)
async def reconstruct_reply_tree(recent_posts):
# make a post + replies entry for each post (replies empty for now)
posts_with_replies_info = [{"post": recent_post, "replies": []} for recent_post in recent_posts]
# create look-up dictionary for the post+replies entries based on the post id
post_with_replies_lookup = {post_with_replies["post"].id: post_with_replies for post_with_replies in posts_with_replies_info}
# start a list that will become our post tree
post_tree = []
# go through all the posts_with_replies_info, and either add them to the post they are in
# reply to (if htey are a reply), or add them directly to the post_tree otherwise
for post_with_replies in posts_with_replies_info:
if(post_with_replies["post"].type == discord.MessageType.reply):
# if post is a reply, find what it is a reply to and add it to the replies list of that post
reply_to_id = post_with_replies["post"].reference.message_id
if reply_to_id in post_with_replies_lookup:
# if we find the post this was a reply to,
# add this post_with_replies to the replies of that post_with_replies info
reply_to_post_with_replies_info = post_with_replies_lookup[reply_to_id]
reply_to_post_with_replies_info['replies'].append(post_with_replies)
else:
# if we couldn't find the post this was in reply to, print warning and
# just add it as a regular post
print("Warning could not find post: " + str(reply_to_id) + ", which message " + str(post_with_replies["post"].id) + " replied to")
post_tree.append(post_with_replies)
else: # not a reply, just add to post_tree directly
post_tree.append(post_with_replies)
return post_tree
Helper function to load the recent posts from channel return the reply tree#
(You don’t need to worry about how this works. This is that function that gets the recent history from a channel, and then uses the reconstruct_reply_tree
function to turn them into a reply tree data structure. By default, the hist_limit
is set to get the most recent 30 posts.)
def get_channel_post_tree(channel_id, hist_limit=30):
# set up discord connection
client = discord.Client(intents=intents)
# Provide instructions for what your discord bot should do once it has logged in
@client.event
async def on_ready():
global reply_tree # Save the reply_tree variable outside our running bot
# Load the discord channel you want to read from
channel = client.get_channel(channel_id)
# Get the latest post in the channel history
post_history = channel.history(limit=hist_limit)
#special code to turn the post_history from discord into a python list
recent_posts = [post async for post in post_history]
reply_tree = await reconstruct_reply_tree(recent_posts)
# Tell your bot to stop running
await client.close()
# Now that we've defined how the bot shoould work, start running your bot
client.run(discord_token)
return reply_tree
Code to print a channel’s recent posts and replies#
The print_channel_post_and_replies
is a function that takes a channel_id, loads the reply post_tree from that channel, and then uses the print_post_and_replies
function to print out all posts and replies. By default, hist_limit
is set to load the most recent 30 posts (but you can change it up to 100).
def print_channel_post_and_replies(channel_id, hist_limit=30):
post_tree = get_channel_post_tree(channel_id, hist_limit=hist_limit)
print("Below are the posts and replies for post from channel " + str(channel_id) + ":" )
for post_with_replies_info in post_tree:
print_post_and_replies(post_with_replies_info)
The print_post_and_replies
function takes a given post_with_replies_info
and recursively prints that post as well as all replies to that post (which will as well as all replies to those replies, etc.)
def print_post_and_replies(post_with_replies_info, num_indents=0):
# for convenience save the post and replies info in variables
post = post_with_replies_info["post"]
replies = post_with_replies_info["replies"]
# save the text to display in a post box
display_text = (
str(post.content) + "\n" +
"-- " + str(post.author)
)
# display the text of this post, indented over
display_indented(display_text, num_indents*20)
#print replies (and the replies of those, etc.)
for reply in replies:
print_post_and_replies(reply, num_indents = num_indents + 1)
Test our code on discord channel#
In order to test it out, we just need to get a discord channel id and pass it to the print_post_and_replies
function. If there are any replies (not threads) in the recent history, we will see them formatted as a reply tree.
print_channel_post_and_replies(5432167890)
Below are the posts and replies for post from channel 5432167890:
I saw a movie once! -- fake_user
I saw one too! -- pretend_user
What a coincidence! -- fake_user
I never saw a movie :( -- imaginary_user
Good morning everyone! -- imaginary_user
Actually, it's night where I am right now. -- pretend_user