Avoid rate limit for changing voice channel name discord js 13 - discord.js

I'm trying to create a slash command using discord.js v13 to change the names of voice channels. I am using this code to do this :
module.exports = {
data: new SlashCommandBuilder()
.setName('name')
.setDescription('Set name for your voice channel')
.addStringOption(option => option.setName('name').setDescription('Enter your name').setRequired(true)),
async execute(interaction) {
const name = interaction.options.getString('name');
if (!interaction.member.voice.channel) await interaction.reply('Error not in a voice channel!');
else {
await interaction.member.voice.channel.setName(name);
await interaction.reply('Done!');
}
},
};
This code is fine and makes the job done. But as you know I can change the voice channel's name only 2 times per 10 minutes because of the limit rate. So if a user tries to change the voice channel's name for the third time, I won't get any error on the console, and discord js will queue this request for later and will do it after 10 minutes. But the user gets this error on discord: This interaction failed.
I want to check if there was a rate limit for my request, and if is, don't send the request and just reply to the user. Is this possible?

There is no inherent functionality that is able to handle the situation in the way you want it to, but the problem is soluble using regular old JavaScript. For example, you could use an integer to indicate how many times the command has been used and use setTimeout() to decrement it 10 minutes after the command was called. That way you can check if the int is equal to 2 in which case you skip the .setName().
There are undoubtedly other ways to implement the same or similar behavior, but, to answer your question, unfortunately the discordjs/voice library does not provide any simple way to do it.

Related

Discord.py Reaction Events

My bot sends an embed every time a new member joins. Then the bot adds the little πŸ‘‹πŸ½ reaction to it. I want members to be able to welcome the new member by reacting. If they react, then they will be rewarded in some way. So onto my question, how would I make my bot watch for reactions for 60 seconds after the embed is sent, and what event would I use? I've found a few things in the documentation but none of which seem to make sense to me. A code example and explanation of how it works would be amazing. Thanks in advance!
In order to do this, you'd need to make use of the on_reaction_add event, assuming you already have all your imports:
#bot.event
async def on_member_join(member): # when a member joins
channel = discord.utils.get(member.guild.channels, name="welcome") #getting the welcome channel
embed = discord.Embed(title=f"Welcome {member.mention}!", color=member.color) #creating our embed
msgg1 = await channel.send(embed=embed) # sending our embed
await msgg1.add_reaction("πŸ‘‹πŸ½") # adding a reaction
#bot.event
async def on_reaction_add(reaction, user):
message = reaction.message # our embed
channel = discord.utils.get(message.guild.channels, name="welcome") #our channel
if message.channel.id == channel.id: # checking if it's the same channel
if message.author == bot.user: #checking if it's sent by the bot
if reaction.emoji.name == "πŸ‘‹πŸ½": #checking the emoji
# enter code here, user is person that reacted
I think this would work. I might have done the indentations wrong since I'm on another device. Let me know if there are any errors.
You can use the on_reaction_add() event for that. The 60 second feature might be complicated.
If you can get the user object from the joined user the on_reaction_add() event, you could check if the user joined less than 60 seconds ago.
You can check the time a user joined with user.joined_at, and then subtract this from the current time.
Here is how to check how many seconds a user is already on the server.
from datetime import datetime
seconds_on_server = (datetime.now() - member.joined_at).total_seconds()
A rather hacky solution is to retrieve the original user who joined through the message on which the reaction is added. Members have the joined_at attribute, which is a datetime object, with it you can just snap current datetime and subtract the former from it. The resulting is a timedelta object which you can use to calculate the time difference.

How to make a slash command bot do not reply messages

#slash.slash(name='spam', description='I will spam your content for times!', options=optionsspam, guild_ids=[847769978308526090])
async def spam(ctx, text: str, times: int="15"):
if bool(times):
Times = 15
else:
Times = times
for i in range(int(Times)):
await ctx.send(text)
await asyncio.sleep(.7)
And the result is:
It keeps replying to the first message that the bot sent. I don’t want the bot to reply. I want it to just send a normal message. How?
An interaction (slash-command) will always require a direct response towards the user. If you do not use ctx.send(str), the interaction will fail.
You've got 2 options to make it seem, like you are not responding to the slash command
Hide the response
You can post a hidden answer ctx.send('ok', hidden=True) and then send the intented message into the channel ctx.channel.send(str).
This will make the initial 'ok' only visible for the invoking users and all other members of the server will neither see the request, nor the first response.
Delete the response
Your second option is to automatically delete the answer after a very short period (ctx.send('ok', delete_after=1)), followed by a normal message into the channel ctx.channel.send(str).
Defering the response
You might need to defer your response if you can't respond within 3 seconds of the invocation. Defering an interaction (ctx.defer(hidden=True) or ctx.defer()) must be called with the same hidden attribute as your future ctx.send().
If you want to hide your respons ctx.send('ok', hidden=True), you need to defer in the same state ctx.defer(hidden=True).
You could get the channel and send message to the channel directly. However, you then must use something like ctx.defer() so that the interaction doesn't get displayed as failed.
#slash.slash(name='spam', description='I will spam your content for times!', options=optionsspam, guild_ids=[847769978308526090])
async def spam(ctx, text: str, times: int="15"):
channel = ctx.channel
if bool(times):
Times = 15
else:
Times = times
for i in range(int(Times)):
if channel != None:
await channel.send(text)
await asyncio.sleep(.7)
await ctx.send("Done")

Discord JS v12: How do you get a message's content by it's ID?

I'm relatively new to discord.js, and I've started building a bot project that allows a user to create a message via command, have that message stored in a hidden channel on my private server, and then said message can be extracted through the message ID.
I have the write working and it returns the message ID of the message sent in the hidden channel, but I'm completely stumped on the get command. I've tried searching around online but every method I tried would return errors like "Cannot read property 'fetch' of undefined" or "'channel' is not defined". Here are some examples of what I tried, any help would be appreciated. Note that my args is already accurate, and "args[0]" is the first argument after the command. "COMMAND_CHANNEL" is the channel where the command is being executed while "MESSAGE_DATABASE" is the channel where the targeted message is stored.
let msgValue = channel.messages.cache.get(args[0])
client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content)
let msgValue = msg.channel.message.fetch(args[0])
.then(message => client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content))
.catch(console.error);
I even tried using node-fetch to call the discord API itself
const api = require("node-fetch")
let msgValue = api(`https://discordapp.com/api/v8/channels/${MESSAGE_DATABASE}/messages/${args[0]}`)
.then(message => client.channels.cache.get(COMMAND_CHANNEL).send(msgValue.content))
.catch(console.error);
Am I missing something or am I making some sort of mistake?
Edit: Thanks for the help! I finished my bot, it's just a little experimental bot that allows you to create secret messages that can only be viewed through their ID upon executing the command :get_secret_message <message_id>. I posted it on top.gg but it hasn't been approved yet, so in the meantime if anyone wants to mess around with it here is the link: https://discord.com/api/oauth2/authorize?client_id=800368784484466698&permissions=76800&scope=bot
List of commands:
:write_secret_message - Write a secret message, upon execution the bot will DM you the message ID.
:get_secret_message <message_id> - Get a secret message by its ID, upon execution the bot will DM you the message content.
:invite - Get the bot invite link.
NOTE: Your DMs must be turned on or the bot won't be able to DM any of the info.
My test message ID: 800372849155637290
fetch returns the result as promise so you need to use the then to access that value instead of assigning it to a variable (msgValue). Also you made a typo (channel.message -> channel.messages).
I would recommend using something like this:
msg.channel.messages
.fetch(args[0])
.then(message => {
client.channels
.fetch(COMMAND_CHANNEL)
.then(channel => channel.send(message.content))
.catch(console.error)
})
.catch(console.error)
I think you were quite close with the second attempt you posted, but you made one typo and the way you store the fetched message is off.
The typo is you wrote msg.channel.message.fetch(args[0]) but it should be msg.channel.messages.fetch(args[0]) (the typo being the missing s after message). See the messages property of a TextChannel.
Secondly, but this is only a guess really as I can't be sure since you didn't provide much of your code, when you try to fetch the message, you are doing so from the wrong channel. You are trying to fetch the message with a given ID from in the channel the command was executed from (the msg.channel). Unless this command was executed from the "MESSAGE_DATABASE" channel, you would need to fetch the message by ID from the "MESSAGE_DATABASE" channel instead of the msg.channel.
Thirdly, if you fetch a message, the response from the Promise can be used in the .then method. You tried to assign the response to a variable msgValue with let msgValue = msg.channel.message.fetch(args[0]) but that won't do what you'll expect it to do. This will actual assign the entire Promise to the variable. What I think you want to do is just use the respone from the Promise directly in the .then method.
So taking all that, please look at the snippet of code below, with inspiration taken from the MessageManager .fetch examples. Give it a try and see if it works.
// We no longer need to store the value of the fetch in a variable since that won't work as you expect it would.
// Also we're now fetching the message from the MESSAGE_DATABASE channel.
client.channels.cache.get(MESSAGE_DATABASE).fetch(args[0])
// The fetched message will be given as a parameter to the .then method.
.then(fetchedMessage => client.channels.cache.get(COMMAND_CHANNEL).send(fetchedMessage.content))
.catch(console.error);

Trying to slow down

I made this command where u can fake hack someone but every time it edits the message too fast I'm just trying to see how can I slow it down where it just plows every single edited message where I cant see
message.channel.send(`Hacking ${votedu.username} now...`).then(msg => {
try {
msg.edit('[β––] Finding discord login... (2fa bypassed)')
msg.edit(`[β–˜] Found:\n**Email:** \`${votedu.username}eatsButt#hotmail.com\`n**Password:** \`1234567890\``);
msg.edit('[▝] Fetching dms with closest friends (if there are any friends at all)');
msg.edit('[β–—] **Last DM:** "I hope no one sees my nudes folder"');
msg.edit('[β––] Finding most common word...');
msg.edit('[β–˜] `const mostCommonWord: string = \'small\';`');
msg.edit('[▝] Injecting trojan virus into discriminator #6218');
msg.edit('[β–—] Virus injected, emotes stolen :pepecreepylurk:');
msg.edit('[β––] Setting up Epic Store account..');
msg.edit('[β–˜] Hacking Epic Store account.... :chugMyJug:');
msg.edit('[▝] Finding IP address');
msg.edit('[β–—] **IP address:** 127.0.0.1:8100');
msg.edit('[β––] Selling data to the Government...');
msg.edit('[β–˜] Reporting account to Discord for breaking TOS...');
msg.edit('Finished hacking Helia');*/
}
```
Your problem is that you didn't wait between the edits.
To wait between each edit, you can use this simple line of code between each message edit.
await new Promise(resolve => setTimeout(resolve, 1000));
You can change 1000 to any number of milliseconds you want.

Is there a way to pm an author and use the wait_for command to capture the value they type in?

I'm writing a discord bot using python to log options trade. What I'm looking to do with my bot is when a user type execute a command, !opentrade, the bot would private message the user with a series of questions. The bot would then capture the answer in a series of variables and use that to process the answer. Is this possible or does it have to be in the channel where the command is called. Additionally, is it by default multithread, meaning 2 or 3 people can call that command at the same time and it would fud up the answer
I have the following thus far and it isn't working:
async def opentrade(ctx):
def check(author):
def inner_check(message):
if message.author != author:
return False
try:
int(message.content)
return True
except ValueError:
return False
return inner_check
try:
await ctx.author.send('Enter the underlying: ')
underlying = await client.wait_for('message', check=check(ctx.author), timeout=30)
print (underlying)
except Exception as err:
await ctx.channel.send("Something went wrong: {}".format(err))
thanks
What I'm looking to do with my bot is when a user type execute a command, !opentrade, the bot would private message the user with a series of questions. The bot would then capture the answer in a series of variables and use that to process the answer. Is this possible or does it have to be in the channel where the command is called.
Possible. You need to put the whole logic into the coroutine that executes the command.
Additionally, is it by default multithread, meaning 2 or 3 people can call that command at the same time and it would fud up the answer
If you implement the checks properly it won't fud the answer. In your code you already implemented the logic that checks for the author so noone else can change it def check(author).
When executing the commands multiple times by different users it will also not fud the answer since the threads are independent.
You should extend this check so it checks for a message in a DM channel. The way your check is written now the caller can DM the bot or respond in a guild text channel.
I'm not sure what's saved in the ctx variable but I'm certain it has a message attribute.
Try await ctx.message.author.send(). If you are running into an error provide the error log.

Resources