Discord.py – User ID from message reaction dump to json file

Question:

I’m looking for a way to store all the user reactions from a message in a json file. I want the users who react with the "✅" to be stored in one json file and the users who react with "❌" to be stored in a separate json file.

This is the portion of the code I’m having trouble with:

for reactions in message.reactions:
  if str(reactions) == "✅":
    user_list = [user async for user in message.reactions.users() if user != client.user]
    for user in user_list:
      users = user.id + "n"
      
      with open ("reaction_tick.json", "w") as f:
        json.dump(users,f)
        return True
for reactions in message.reactions:
  if str(reactions) == "❌":
    user_list = [user async for user in message.reactions.users() if user != client.user]
    for user in user_list:
      users = user.id + "n"
            
      with open ("reaction_cross.json", "w") as f:
        json.dump(users,f)
        return True

How do I gather all the users’ ids and put them into a string then dump that into a json file?

So far, when I run all the code nothing happens and there are no error messages.

Any help would be greatly appreciated.

================================================================
Here is the rest of my code:

@client.event
async def on_member_join(member):
  
  channel = client.get_channel(1003203232824307745)
  
  embed=discord.Embed(title=f'{member.name}#{member.discriminator} has joined the server!', description="Will they stay or will they leave? Place your bets!", color=0xf1c40f, inline=True)
  embed.add_field(name='Will they stay longer than 1 hour?', value=f'React stay ✅')
  embed.add_field(name='Will they leave before 1 hour is up?', value=f'React leave ❌')
  embed.add_field(name='Betting will close in:', value=f'5 minutes', inline=False)
  embed.add_field(name='Results will be posted in', value=f'1 hour!', inline=True)
  
  message = await channel.send(embed=embed)
  await message.add_reaction('✅')
  await message.add_reaction('❌')

  time = 3600 
  id = member.id

 
  while time >= 0:
    if time <= 0:
       embed.remove_field(index=3)
       embed.insert_field_at(index=3, name='Betting complete! Results have been posted!', value=f'Ended at {datetime.datetime.now().strftime("%B %d, %I:%M %p")}', inline=False)
       await message.edit(embed=embed)
       await membercheck(id, channel)
       await reactioncheck(message)
       return
    elif 1 <= time < 50:
      embed.remove_field(index=3)
      embed.insert_field_at(index=3, name='Results in:', value=f'{time:.1f} seconds', inline=False)
      await message.edit(embed=embed)
      time -= 10
      await asyncio.sleep(10)
    elif 60 == time:
      embed.remove_field(index=3)
      embed.insert_field_at(index=3, name='Results in:', value=f'{time/60:.1f} minute', inline=False)
      await message.edit(embed=embed)
      time -= 10
      await asyncio.sleep(10)
    elif 60 <= time < 3290:
      embed.remove_field(index=3)
      embed.insert_field_at(index=3, name='Results in:', value=f'{time/60:.1f} minutes', inline=False)
      await message.edit(embed=embed)
      time -= 10
      await asyncio.sleep(10)  
    elif 3300 == time:
      await reactioncheck(message) #This is the function that I was having trouble with above. 
      embed.remove_field(index=2)
      embed.insert_field_at(index=2, name='Betting has closed:', value=f'Ended at {datetime.datetime.now().strftime("%B %d, %I:%M %p")}', inline=False)
      await message.edit(embed=embed)
      await message.clear_reactions()
      time -= 10
      await asyncio.sleep(10)  
    elif 3300 <= time < 3600:
      await reactioncheck(message)
      embed.remove_field(index=2)
      embed.insert_field_at(index=2, name='Betting will close in:', value=f'{time/60 - 55:.1f} minutes', inline=False)    
      embed.remove_field(index=3)
      embed.insert_field_at(index=3, name='Results in:', value=f'{time/60:.1f} minutes', inline=False)
      await message.edit(embed=embed)
      time -= 10
      await asyncio.sleep(10)

async def reactioncheck(message):        
  rmsg = message #the message with reactions
  for reaction in rmsg.reactions:
    users = "" #the string to dump
    if str(reaction) == "✅":
      user_list = [user async for user in reaction.users() if user != client.user]
      #it should be reaction.users() and not <message>.reactions.users()
      for user in user_list:
        users = users + str(user.id) + "n" #converting ID to str and adding instead of overwriting
                  
        with open("reaction_tick.json", "w") as f:
            json.dump(users, f)
            return True
  for reaction in rmsg.reactions:
    if str(reaction) == "❌":
      user_list = [user async for user in reaction.users() if user != client.user]
      for user in user_list:
        users = users + str(user.id) + "n"
                  
        with open("reaction_cross.json", "w") as f:
          json.dump(users, f)
          return True

I know there are many issues with this and I know I should create other helper functions in order to condense this mess. The general gist of what I’m trying to achieve is that upon a new member joining my server, my bot will send an embed to a designated channel. The embed has a timer that constantly updates until that timer is finished. There are 2 timers on the embed – the first lasts 5 minutes and the second lasts 1 hour. When the first timer finishes, I want my bot to store the names of the people who have reacted to the embed and then clear the reactions from the embed. After the second timer is finished, the embed will send the names of the people who reacted with the ✅ and ❌ emojis. Basically people are betting on whether new members will stay or leave the server within the given hour.

Asked By: Swag Snags

||

Answers:

You made a silly mistake in the line used to create user_list. It’s reaction.users(), not <message>.reactions.users(). You are trying to call a function users() of a list object which does not exist (a list obviously doesn’t have a .users() function). In other words, you are trying to use users() on the wrong object. message.reactions is a list (it returns a List[Reaction]). You are trying to run list.users(), which is invalid.
I’ve corrected the code:

for reaction in message.reactions:
  if str(reaction) == "✅":
    user_list = [user async for user in reaction.users() if user != client.user]
    #it should be reaction.users() and not <message>.reactions.users()
    for user in user_list:
      users = users + str(user.id) + "n" #converting ID to str and adding instead of overwriting
      
      with open ("reaction_tick.json", "w") as f:
        json.dump(users,f)
        return True
for reaction in message.reactions:
  if str(reaction) == "❌":
    user_list = [user async for user in reaction.users() if user != client.user]
    for user in user_list:
      users = users + str(user.id) + "n"
            
      with open ("reaction_cross.json", "w") as f:
        json.dump(users,f)
        return True

Note that I’ve replaced reactions with reaction in the for loops (so that I don’t make mistakes). You can correct them back if you want; just make sure you correct them in other places too.

Here is an example of how to use this code:

from discord.ext import commands
import discord.utils
import json

intent = discord.Intents(messages=True, message_content=True, guilds=True)

bot = commands.Bot(command_prefix="", description="", intents=intent)

@bot.event
async def on_ready(): #When the bot comes online
    print("It's online.")

@bot.command(name="gr")
async def gr(message, msg):
    if msg == "message":
        
        rmsg = None #the message with reactions
        
        async for msg in message.channel.history(limit=200):
            if msg.content == "message":
                rmsg = msg
        
        for reaction in rmsg.reactions:
            users = "" #the string to dump
            if str(reaction) == "✅":
                user_list = [user async for user in reaction.users() if user != bot.user]
                #it should be reaction.users() and not <message>.reactions.users()
                for user in user_list:
                    users = users + str(user.id) + "n" #converting ID to str and adding instead of overwriting
                    
                    with open("reaction_tick.json", "w") as f:
                        json.dump(users, f)
                        return True
        for reaction in rmsg.reactions:
            if str(reaction) == "❌":
                user_list = [user async for user in reaction.users() if user != bot.user]
                for user in user_list:
                    users = users + str(user.id) + "n"
                    
                    with open("reaction_cross.json", "w") as f:
                        json.dump(users, f)
                        return True

bot.run(<token>)

You can send a message on Discord (manually) and react to it with the emojis (for testing). Replace "message"s with the content of the message which you sent manually. rmsg is the message (to which you also reacted manually). users is the string that’s going to be dumped as a JSON. Also, I’ve replaced users = user.id + "n" with users = users + str(user.id) + "n". Your code overwrites users every time in the for loop. Also, you can’t concatenate a string (users in my case) with an integer (user.id).

Do you not get any errors or exceptions? Because I got many.

Answered By: The Amateur Coder
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.