How can I properly upload too long messages as a file? - discord

I was doing some research on Discord's capabilities today, and then I noticed that the "upload as file" option is given when a message is more than 2000 characters long.
The number plays a role here, but my statement can also be wrong, the fact is that some things are posted only as a link and or then not sent at all if I raise >2000.
Here now the problem:
I am requesting data from Genius for a lyrics command. I already have some kind of override built in for when len(data["lyrics"]) is greater than 2000 "characters", that should be Discord's limit after all, otherwise the bot wouldn't be able to process the embed I am trying to send.
How can I manage that lyrics >2000 are sent as a file?
Relevant code:
if len(data["lyrics"]) > 2000:
return await ctx.send(f"<{data['links']['genius']}>"))
This is the normal request, it works too, but it just throws out the link.
I then tried to send this via discord.File with the corresponding piece of code above, does not work. (Something like file=discord.File(data) was tried too!)
Something like ctx.file.send does not work in this case either
The following posts were viewed:
Uploading a file in a embed discord.py (not a image)
Discord.py - Sending a text file on DM
Discord.py Bot sending file to Discord Channel
Python discord.py ways to split output to bypass 2000 character limit
What I want my bot to do if data["lyrics"] > 2000:

You can save the text into a io.StringIO buffer and pass that into the discord.File constructor:
from io import StringIO
text = data["lyrics"]
if len(text) > 2000:
buffer = StringIO(text)
f = discord.File(buffer, filename="lyrics.txt")
await ctx.send(file=f)

Related

Can't get my Discord bot to connect to voice channel

I'm messing around with a bot for the first time but can't seem to get it to join a voice channel. I know the $join command is working because my bot will say "Connecting to {channel}" with the correct channel name, but it still never connects. If I'm not in a voice channel, the bot will correctly say "Error".
I've tried every single solution I can find online. Every time the bot will identify the correct channel but it simply won't join the channel. This feels like such a simple problem so I'm not sure how I can use similar code as others and still not have it work. Below is the code I'm using for the command. I left out all the prefix and bot setup code because all the messages I send work fine.
#bot.command()
async def join(ctx):
if (ctx.author.voice):
channel = ctx.message.author.voice.channel
await ctx.send(f"Connecting to {channel}")
await channel.connect()
else: await ctx.send("Error")
asyncio.TimeoutError – Could not connect to the voice channel in time.
discord.ClientException – You are already connected to a voice channel.
discord.OpusNotLoaded – The opus library has not been loaded.
These are the following errors that the bot can raise for VoiceChannel.connect()
If you are not receiving errors when you should, this points towards a poorly made global command handler on_command_error.
You either want to remove that for the time being to get the actual error on the console, or fix it by output the error in a case where the error isn't handled. A common way of doing that is:
import sys
import traceback
#bot.event
async def on_command_error(ctx, error):
if x: # let x, y, z be isinstance check for error
# do this
elif y:
# do that
elif z:
# idk do something other than this and that
else:
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
After getting your actual error for joining the VC, check through these:
asyncio.TimeoutError: This error is raised when your bot has a
weak internet connection or your ping is absurdly high, high enough
to not make a connection.
discord.ClientException: Might want to check if bot is not in VC when it starts up, and also that you have relevant guild intents and voice intents enabled.
discord.OpusNotLoaded: Your device does not have libopus loaded, you might want to search for that online depending on what you use. If you are on an ubuntu-based linux distro, you can use sudo apt install libopus0 and then try to see if it fixed your issue. I am not sure about windows
If you can't figure it out after you read the above stuff, let me know the EXACT ERROR you are facing, which includes the traceback message (the whole error text that will print onto your console)

How to add reactions to messages in discord.py without id

I am new to discord.py coding. I can't find the I'd for arrow up emoji... I've tried client.emojis and others but it doesnt work... pls help or send me all the ids or a website to see all the ids
just type your emoji in :this: form and stic an \ before the emojiname thats it!
when you send it it will come as <:something:1234567890123>
copy the numbers at the end thats your emoji id
same can be done with members and channels just instead of :this: do :#random_dude: and for channels do #general
hope this helps! Goodluck on your development!
I'm not sure what your code looks like, but if you're interacting with your 'message' asyncs you could do this.
emoji = '\N{THUMBS UP SIGN}'
# or '\U0001f44d' or 'πŸ‘'
await message.add_reaction(emoji)
If you can, can you add your code so I can see where your error might be?
As zjbrown said, the thumbs up emoji can be stored in a string (and sent) using "\N{THUMBS UP SIGN}", "\U0001f44d", or "πŸ‘".
You can google a built-in emoji's name to find websites that have emoji descriptions. Sometimes these sites also have the unicode name, but this is not guranteed. If you want to send a custom emoji, you will have to find the emoji's id.
For built-in emojis, you can use RoboDanny's charinfo command (you'll have to add it to your own bot or use the RoboDanny bot in the discord.py support server) to get the unicode name.
If it is a custom emoji, you can send it in chat and get the image url (right click -> copy url). Then, look for the string of numbers before the .png and copy that. (Numbers only - don't copy the beginning of the url!) You can then send custom emojis by using the string <:[emoji name]:[emoji id]> for static emojis and <a:[emoji name]:[emoji id]> for animated emojis.

Avoid rate limit for changing voice channel name discord js 13

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.

Unable to retrieve attachments from a signed mail having ContentType as "application/pkcs7-mime; name=smime.p7m"

I am trying to read a digitally signed mail from java code using multipart and mime messaging and fetch the attachments (xml, pdf, txt etc.,) and message details.
My code is working fine for mails having Content-Type as : multipart/signed; protocol="application/x-pkcs7-signature";
But For few mails having Content-Type as : application/pkcs7-mime; smime-type=signed-data; name=smime.p7m it is not fetching the attachments and message details. Can anyone explain what is the difference between both of them and how to resolve it.
I recently came across this issue myself, and although this question is three month old, I leave an answer with my findings, just in case.
Both kinds of messages are instances of S/MIME signed messages as specified in RFC2633 (https://www.rfc-editor.org/rfc/rfc2633).
The multipart/signed; protocol="application/x-pkcs7-signature" indicates a clear-signed message (section 3.4.3.3 of the RFC), meaning you can read the original message content without having S/MIME capabilities in your client code. Hence no problem with these.
The application/pkcs7-mime; smime-type=signed-data; name=smime.p7m indicates an S/MIME signedData email (section 3.4.2) Your client code needs S/MIME capability in order to read the original message (even if you don’t care about the signature).
Easiest way (worked for me) is to use bouncycastle's SMIMESigned class (from the S/MIME API, https://mvnrepository.com/artifact/org.bouncycastle/bcmail-jdk15on), like this:
byte[] content = <the signed data's content as byte[]>;
ByteArrayDataSource dataSource = new ByteArrayDataSource(content,"multipart/signed");
SMIMESigned signedData = new SMIMESigned(new MimeMultipart(dataSource));
MimeBodyPart bodyPart = signedData.getContent();
<you can process the body part as normal from here>

Deleting certain file type attachments in a specific channel?

I'm trying to add certain files from being posted to the general channel as we have designated channels for certain attachments, clips, videos, music, etc. I'm fine on getting the bot to recognize links, however, having a hard time getting it to recognize attachments, more specifically, .mp4 attachments.
I added a whitelist of acceptable attachments in an array, then try and check the message author attachment to see if it's okay to post, if its an .mp4 it should be deleted.
The try function is within the on_message event decorator.
whiteList = ['bmp','jpeg','jpg','png']
try:
for attachment in message.attachments:
#Get general channel ID
channel = client.get_channel(521376573245358081)
if message.channel is channel and attachment['filename'].split('.')[-1] not in whiteList:
await message.delete()
botsMessage = await channel.send("{0.mention} Please refrain from posting videos in General. You may post them in #videos".format(message.author))
await asyncio.sleep(5)
await botsMessage.delete()
except:
print('Unknown error')
No error comes of this as when I test this the attachment remains, the bot passes over the function and prints the console message (used for debugging to make sure the code reaches that far). Any suggestions?
attachment['filename'].split('.')[-1]
You treated attachment as an dictionary that has a key called filename.
You should have treated attachment as an object that has a property called filename as follows:
attachment.filename.split('.')[-1]
Also, you should break the loop whenever the message is deleted,
# ...
botsMessage = await channel.send("{0.mention} Please refrain from posting videos in General. You may post them in #videos".format(message.author))
await asyncio.sleep(5)
await botsMessage.delete()
break
# ...
in the event that the user have sent mutiple video files, the loop will still continue even after you delete the message. Which may cause it to try to delete a deleted message
The break statement prevents the above from happening.

Resources