How to update a Python string in a for loop? - python

I am building a Discord bot using the discord.py library. The library uses the on_message(ctx) event to let us modify a message if we want to. What I would like to do is to remove the formatting and replace the user mentions with the Discord names. The text of the message looks like this:
<#!34565734654367046435> <#!34565734645354367046435> are you here?
In the ctx variable I can get the mentions as User objects from ctx.mentions and I can get the NAME and the ID of each mentioned user.
I'd like to replace the <#!34565734654367046435> with the name of the user. The result to be something like:
Name1 Name2 are you here?
This is what I have so far but it does not seem to work.
remove_formatting = utils.remove_markdown(context.content)
print(remove_formatting) # prints the very first code styled line in this question
for member in context.mentions:
remove_formatting.replace(f'<#!{member.id}>', member.name)
If I print the member.id and the member.name without doing anything else, I get the expected values. How do I update the string in this for loop?

The replace function returns a new string, it doesn't edit the existing string in place. If you edit your loop to:
remove_formatting = utils.remove_markdown(context.content)
for member in context.mentions:
remove_formatting = remove_formatting.replace(f'<#!{member.id}>', member.name)
it should work.

Related

Is there a way to read a value of a specific field in an embed discord.py

So I have an embed like in the picture, I would like to get the user id from that embed, is there any way to do it?
What have I tried so far:
to_dict With Discord.py, is there a way to read embedded messages? Couldn't get to the value of the field
.fields https://discordpy.readthedocs.io/en/latest/api.html?highlight=#discord.Embed.fields same result as to_dict
.set_field_at https://discordpy.readthedocs.io/en/latest/api.html?highlight=#discord.Embed.set_field_at didn't work, required me to change the value
set_field_at() is a function that will update the contents of a field. You will not be able to retrieve the contents with this method.
You can still use .fields. You can put something similar to the following in the method of your choice.
embed = # Put the Embed in the picture as a discord.Embed object and assign it to this variable
for field in embed.fields: # Dynamically get the user id field.
if field.name.lower() == "user id": # I recommend copying and pasting the field of choice, just in case the characters are not the same visually.
user_id_field = field
break
else: # In case the field isn't found
pass # Put some code here
user_id = int(user_id_field.value) # Get the value of the field
# Either send or print it
References:
discord.Embed.fields - Get a list of the fields from an embed.
discord.Embed.add_field() - denotes the attributes from a field

How to check if a string is a discord name in python?

I have a sheet where I'm sorting different columns and I have a column where there are supposed to be only discord names(example: name#0000).
Can I check that with discord.py, if not how should I check it?
You can use the If string in string syntax in Python.
For example:
If "#" in name:
do something
You can get the name in the following way.
Let's say you want to check when a player joins your server:
async def on_member_join(member):
if find_in_record(member.name):
do something
else:
kick_member() //Depends on you
The member.name property will return you a str which will be the name (in name#XYZW).
For the find_in_record function you can use the xlrd module

My Discord XP bot isn't recognizing user data in JSON files?

My bot is not working as planned.
For the context of the bot, I followed a YouTuber's tutorial almost exactly (other than the algorithm for the experience) - https://www.youtube.com/watch?v=pKkrCHnun0M&t=890s
async def update_user(users, user):
if not user.id in users:
print('added new user')
users[user.id] = {}
users[user.id]['experience'] = 0
users[user.id]['level'] = 1
async def add_xp(users, user, exp):
print('added exp')
users[user.id]['experience'] += exp
I added the print function so I could track which functions have been triggered.
The first time, it worked. User data popped up in my users.json file when i typed in the channel. However, upon the second time typing anything, this happens:
It showed the same data being input twice! I was so confused because everything is the same. I will post the full code of the bot in here. Please help me make the bot possible to use.
https://pastebin.com/BkzSbVan (I removed the server ID and channel ID, so please focus on the functions)
The JSON standard requires keys to be strings, so when you use json.dump, it converts the integer IDs into strings. However, when you load that back with json.load, it stays a string, so the user dictionary will have string keys when you load it from the file. Then, when you check if the user ID is in the dictionary, it's by integer, so it's not, and it adds the integer ID as a key for the dictionary with a new initial value. At this point, you have an integer and string version of the same ID in your dictionary. When you write this back to the file with json.dump, it again converts the integer ID to a string, resulting in what you see in your screenshot.

How should I use parse_mode='HTML' in telegram python bot?

I'm trying to send a message in a channel with a bot, using Telegram API's send_photo() method. It takes a caption parameter (type String) but I can't format it through parse_mode='HTML' parameter...
If I use something like this:
send_photo(chat_id, photo, caption="<b>Some text</b>", parse_mode='HTML')
it sends the message but without any kind of formatting. Does anybody know why? Thanks
First, you need to import ParseMode from telegram like this:
from telegram import ParseMode
Then, all you need is to specify parse_mode=ParseMode.HTML. Here's a working example:
def jordan(bot, update):
chat_id = update.message.chat.id
with open('JordanPeterson.jpg', 'rb') as jordan_picture:
caption = "<a href='https://twitter.com/jordanbpeterson'>Jordan B. Peterson</a>"
bot.send_photo(
chat_id,
photo=jordan_picture,
caption=caption,
parse_mode=ParseMode.HTML
)
And we can see that it works:
Update: Actually, both parse_mode='html' (as suggested by #slackmart) and parse_mode='HTML' that you used yourself work for me!
Another Update (as per your comment): You can use multiple tags. Here's an example of one, with hyperlink, bold, and italic:
Yet Another Update: Regarding your comment:
...do I have any limitations on HTML tags? I can't use something like <img> or <br> to draw a line
Honestly,
That's what I did!
Now you're trying to format the caption of an image, using HTML, meaning you're formatting a text, so obviously, you can't use "something like <img>." It has to be a "text formatting tag" (plus <a>). And not even all of them! I believe you can only use these: <a>, <b>, <strong>, <i> and <em>.
If you try to use a text-formatting tag like <del>, it will give you this error:
Can't parse entities: unsupported start tag "del" at byte offset 148
Which is a shame! I'd love to be able to do something like this in captions of images.or something like this!
It works for me! Here's the code I'm using:
>>> from telegram import Bot
>>> tkn = '88888:199939393'; chid = '-31828'
>>> bot = Bot(tkn)
>>> with open('ye.jpeg', 'rb') as fme:
... bot.send_photo(chid, fme, caption='<b>Hallo</b>', parse_mode='html')
...
<telegram.message.Message object at 0x7f6301b44d10>
Of course, you must use your own telegram token and channel id. Also notice I'm using parse_mode='html' # lowercase

How can I properly parse for a tagged user in my Discord bot?

I am adding profile cards onto my Discord bot, but I've come across one issue. When someone types !profile #user I am not sure how to properly parse for #user so the bot knows which profile card to lookup.
I first parse message.content and then remove the 9 first chars of the message content (which is always !profile) but the rest of the message content returns the user_id which looks <#289583108183948460> instead of the user's discrim. I have tried using re.sub to remove the special characters (#, >, and <) like this:
a = str(message.content[9:])
removeSpecialChars = re.sub("[!##$%^&*()[]{};:,./<>?\|`~-=_+]", " ", a)
print(removeSpecialChars)
But the weird characters are still there when I only want the number so I can search it in the database easily. I'm sure there's a way better way to do this though but I can't figure it out.
discord.py's message objects include a Message.mentions attribute so you can iterate over a list of Member. Here are the doc listings for async and rewrite.
With this you can simply iterate over the mentions as so:
for member in ctx.message.mentions:
# do stuff with member
what you actually want
discord.py allows you to grab discord.Member objects from messages with type hinting. simply add the following to the command
#bot.command()
async def profile(ctx, member: discord.Member=None):
member = member or ctx.message.author

Categories

Resources