Migrating message embeds code to the 1.0 version - python-3.x

I had made a discord bot a while back for a purpose involving message embeds that my friends and I needed. Long story short the bot went offline for like a year because the host (a raspberry pi) died. Fast forwarding today, we needed it again so I tried it firing it up, but noticed that most of my code doesn't work anymore, because the async branch of discord.py has been updated to v1.0 which brings major changes and requiers migration in code to comply with the new library. Looking at the documentation, I was able to figure everything out, except the embed part of my bot. Which is the most important.
This is the code I will focus on, there is more after, but it's irrelevant to this part, because if I can sucessfully store the values I am aiming for in the string, then the rest should work.
async def on_message(message):
serverid = message.guild.id
channel = message.channel
messagecontent = message.content
if message.embeds:
try:
charaname = message.embeds[0]['author']['name']
charaseries = message.embeds[0]['description']
except AttributeError:
return
What I am basically trying to do, is if a message has an embed, then I need to store the name and description values in seperate strings, for later on use in the code. But I get this trying to do so:
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\discord\client.py", line 270, in _run_event
await coro(*args, **kwargs)
File "C:\path_to_script", line 35, in on_message
charaseries = message.embeds[0]['description']
TypeError: 'Embed' object is not subscriptable
Some research showed to me that 'subscriptable' means when an object can contain multiple other objects, such as lists. It's explained here better. If it's not subscriptable, then I am guessing the new library has a whole new way of handling this, which I cannot seem to figure out. So I need help understanding what exactly is going on here, so I can adapt my code and get this part working again.
Help is appreciated alot, thank you!

TypeError: 'Embed' object is not subscriptable as you can see Embed is a object and it is not subscriptable.
One of the examples of the subscriptable object is a standard dictionary. This means it's atribbutes can be accessed with ["key_name"].
For other objects to be subscriptable they need to implement the __getitem__() dunder method. Since you're getting object not subscriptable error it means that your Embed object does not implement this method.
You used to be able to access them in that way but if you look at d.py migrating page you will see that they state:
Message.embeds is now a list of Embed instead of dict objects.
So it's a list of Embed objects and if you look at current Embed documentation you will see how to access it's atributtes - for your case:
charaname = message.embeds[0].author.name
charaseries = message.embeds[0].description
So for clarification message.embeds is a list of Embed objects so with [0] we get the first element from that list, which is a Embed object.
As you can see from the documentation we can access it's description with description attribute, simple isn't it?
And if we do .author ,as seen from the documentation, we will access it's author EmbedProxy object. Now what can we access from this? If you look up the previous documentation link it states See set_author() for possible values you can access.
So let's see the documentation for set_author() , as we can see it's parameters are
name (str)
url (str)
icon_url (str)
So going by previous statement from the docs we know we can access those 3.
So this is all valid:
message.embeds[0].author.name
message.embeds[0].author.url
message.embeds[0].author.icon_url
If any of those are not set it will return Embed.Empty as seen from the docs
So if they are not set you will get Embed.Empty , one example of such embed is:
embed = discord.Embed(title="Test embed #1", description="Some description")
await ctx.send(embed=embed)
As you see the author is not set so if you fetch message.embeds[0].author.name you will get Embed.Empty while for message.embeds[0].description you will get Some description because it was set.
One example for setting author in embed:
embed = discord.Embed(title="Test embed #2", description="Some description").set_author(name=ctx.author.name)
await ctx.send(embed=embed)
(we used set_author()) - this will get us string for author name since it is set during Embed initialization.

Related

Godot, GDScript - Play Animation on Right Click

Any insight onto why this code doesn't work?
When I right click, the game crashes and gives the error: "Invalid call. Nonexistent function 'play' in base 'Array'".
func _ready():
anim_Play = get_tree().get_nodes_in_group("AnimationPlayer")
func_input(event):
if Input.is_action_pressed("aim"):
anim_Play.play("AimSights")
I guess from your code that you are trying to get a reference to your AnimationPlayer node, it fails and you get an Array instead.
It happens because you are using get_nodes_in_group (which returns an Array of nodes in a group), instead of get_node, which returns a node.
Invalid call. Nonexistent function 'play' in base 'Array
Means your are trying the call the play method (found in AnimationPlayer) from an Array object, that does not exist.
You would get AnimationPlayer like
var anim_Play = get_node("./path/to/your/AnimationPlayer")
Response to your question
get_nodes_in_group(group) returns an Array of nodes that are both in the SceneTree and in group group.
Let's say there is one AnimationPlayer node in the group "AnimationPlayer". We'll fetch it like:
var anim_player = get_tree().get_nodes_in_group("AnimationPlayer")[0]
Notice the [0]. That is called an accessor. We access the array at element 0. Now, we can call play:
anim_player.play("AimSights")
Do note: it is an error to access a non-existent element of an array.
Recommendation
This seems like an inappropriate use of groups. I recommend you use a node path, like svarog suggested, if the animation player is in the same scene as the script.
Additionally, it will help to read or google about some fundamental programming concepts: specifically Objects and Arrays.
Lastly, read over the scenes and nodes page from Godot's documentation: https://docs.godotengine.org/en/3.1/getting_started/step_by_step/scenes_and_nodes.html
The whole getting started guide on the Godot's documentation is an invaluable resource for learning Godot. It will help you greatly and it's not too long of a read.
Good luck!

How to mention the author of a message in another message

I am using repl.it to develop a bot. I am trying to make a command that makes the bot behave like this:
Someone: !slap #someoneelse
Bot: #Someone slapped #someoneelse
How can I get the bot to mention #someone without using ID? Multiple people will use the command and I can't just use ID since it will only work with one person. I haven't found anything that helped me, and the documentation was no help either. Hopefully, I can get help! Thank you.
Users and members have a .toString() method that is automatically called every time they are concatenated with a string: that means that if you type "Hey " + message.author you will get "Hey #author"
That's how I would do the command:
// First store the mentioned user (it will be undefiend if there's none, check that)
let mentionedUser = message.mentions.users.first();
// Reply by directly putting the User objects in the string:
message.channel.send(`${message.author} slapped ${mentionedUser}`);

message filter for bot's messages undefined node.js

I am having a bot set up the beginnings of a game. A human inputs the command of /startbrawl to initiate the setup of the game (creating the deck objects). But the two players need to be identified first. I have a message sent from another command that says "Player A is #[username A]. Player B is #[username B]." in the channel this game is happening in. I want the bot from this new command to look at the first message sent in the channel, which is always the "Player A is etc..." message (and is always sent by the bot) and pull both usernames from it in order to specify for this new command who is player A and who is player B. The code I have most recently (after trying multiple things) is this:
if (userInput.startsWith("!startbrawl") === true) {
message.channel.fetchMessages().then(messages => {
const botMessages = messages.filter(message => message.author.bot);
console.log(botMessages.mentions.members.first()) //this will be Player A. I'd repeat same for Player B with .last instead.
}
}
This gives me an error:
(node:15368) UnhandledPromiseRejectionWarning: TypeError: Cannot read
property 'first' of undefined.
I have made the last line be console.log(botMessages) to get all the info about the messages the filter finds. But trying to extract only part of it gives issues about not being defined, or just a result of undefined with no errors. Either way, something isn't working how I think I need it to.
The only other thing I've debated trying is exporting variables from the command prior to this new command. Player A and Player B are defined in the command used to make the channel that this new command is then used in. However, I've never had luck with exporting variables when I've used it in other instances. I use a command handler, so I'm not sure if that affects how exporting variables works... Which method would work best to set up the card game? I'm a novice in general just figuring things out as I go, so some advice (beyond take a course, look up basics, etc) is greatly appreciated. I've taken an online course for javascript and I work best figuring things out first hand.
Thanks for the help in advance!
As botMessages is a collection you wanna get a Message object out of it by doing
botMessages.first()
So try logging something like
botMessages.first().mentions.members.first()

Discord Bot cannot access text files

Long story short, I have been working in a bot for the past month but I had all of my commands on on_message listeners instead of context and command decorators, so I decided to do it properly, in the process of transferring my commands numerous changes have been needed, but this one has me puzzled.
The way I store user information is in text files, unfortunately on the new way of doing things it seems that I cannot access text files anymore, I looked at this code over and over and tried to troubleshoot it by making sure strings aren't empty and such, the more I looked into it the more I realized that there isn't anything wrong with it, based on other information i've looked up online, the only reason I could think of is because code is inside an async function which causes it to not work. It does not throw any exceptions for anyone wondering
If this is indeed the case, what would I have to do to fix it?
Current code:
userid = 'userfiles/' + ctx.message.server.id + '/' + ctx.message.author.id + '.txt' #get path based on user ID
try:
userfile = open(userid, 'a') #open the file from
userfile.write(i)
userfile.close()
except IOError:
await client.send_message(ctx.message.channel, 'Irrecovarable exception encountered')
return

discord python deleting bot messages

So i'm just getting into python and Discord and i want to know if it is possible to delete only the messages from the bot. I already have a script that has an error, 'list' object has no attribute 'channel'
if message.content.startswith('!clearbeta'):
list = ['!8ball', '!uptime', '!meme', '!animated meme', '!weeb', '!cute af', '!coin', '!fun', '!reaction']
await client.delete_message(list)
await client.send_message(message.channel, "Cleared messages")
It would help if you read the documentation, I suppose.
client.delete_message needs a Message object, not a list of strings. Similarly, client.delete_messages needs a list of Message objects.
You could instead use something like client.purge_from with a check predicate to test if the message content matches something in your list. However, the endpoint for purging has a limit of <= 2 weeks (ie, you can't delete messages older than this).

Resources