I was making a discord bot using NodeJS, and everytime i go boot up the bot it shows this error:
headers = (await fetch(filtered.fileUrl, { method: 'HEAD' })).headers
^^^^^
SyntaxError: Unexpected identifier
What i knew is that, fetch requires node-fetch. At first, i thought the problem was that i was using node-fetch#3.0.0, which doesn't support const fetch = require('node-fetch') but even when i downgraded it to node-fetch#2.6.1 this exact issue still persists.
Full code:
const fetch = require('node-fetch')
const Booru = require('booru')
const Discord = require('discord.js')
const { escapeMarkdown } = Discord.Util
const path = require('path')
const Color = `RANDOM`;
module.exports = {
info: {
name: "booru",
description: "booru image scraper",
cooldown: 30,
},
async execute(client, message, args, Discord) {
const tag_query = args.join(' ');
if (!message.content.includes('help')) {
if (!message.content.includes('something')) {
const hornyEmbed = new Discord.MessageEmbed()
.setTitle('embed cut to preserve space')
if (!message.channel.nsfw) return message.channel.send(hornyEmbed)
Booru.search('gelbooru', tag_query, {
limit: 1,
random: true
})
.then(posts => {
const filtered = posts.blacklist(['blacklist, of course.'])
if (filtered.length === 0) {
const notfoundEmbed = new Discord.MessageEmbed()
.setDescription("embed cut to preserve space")
message.channel.send(notfoundEmbed)
}
let tags =
filtered.tags.join(', ').length < 50
? Discord.Util.escapeMarkdown(filtered.tags.join(', '))
: Discord.Util.escapeMarkdown(filtered.tags.join(', ').substr(0, 50))
+ `... [See All](https://giraffeduck.com/api/echo/?w=${Discord.Util
.escapeMarkdown(filtered.tags.join(',').replace(/(%20)/g, '_'))
.replace(/([()])/g, '\\$1')
.substring(0, 1200)})`
let headers
let tooBig = false
let imgError = false
try {
headers = (await fetch(filtered.fileUrl, {
method: 'HEAD'
})).headers
} catch (e) {
imgError = true
}
if (headers) {
tooBig = parseInt(headers.get('content-length'), 10) / 1000000 > 10
}
for (let post of posts) {
embed_nsfw = new Discord.MessageEmbed()
.setTitle('you horny')
.setColor('#FFC0CB')
.setAuthor('-')
.setDescription(`-` +
`**Provided by:** Gelbooru.com | `, +`[**Booru Page**](${filtered.postView}) | ` +
`**Rating:** ${filtered.rating.toUpperCase()} | ` +
`**File:** ${path.extname(filtered.file_url).toLowerCase()}, ${headers ? fileSizeSI(headers.get('content-length')) : '? kB'}\n` +
`**Tags:** ${tags}` +
(!['.jpg', '.jpeg', '.png', '.gif'].includes(
path.extname(filtered.fileURL).toLowerCase(),
) ?
'`The file will probably not embed.`' :
'') +
(tooBig ? '\n`The image is over 10MB and will not embed.`' : '') +
(imgError ? '\n`I got an error while trying to get the image.`' : ''),
)
.setImage(filtered.sampleUrl)
message.channel.send(embed_nsfw);
}
})
}
if (message.content.includes('something')) {
const helpEmbed = new Discord.MessageEmbed()
.setTitle('cut to preserver space')
message.channel.send(helpEmbed)
}
}
if (message.content.includes('help')) {
const helpEmbed = new Discord.MessageEmbed()
.setTitle('cut to preserver space')
message.channel.send(helpEmbed)
}
}
}
I know this code is extremely messy, because it's basically a frankenstein's code put together from different codes i found. So aside from the solution for the main topic, a pointer on another issue i hadn't noticed will also be appreciated.
NodeJS version 16.13.0,
NPM version 8.1.0,
DiscordJS version 12.5.3,
Running on a Heroku server.
try add async to .then(posts => .
Booru.search('gelbooru', tag_query, {
...
.then(async posts => {
const filtered = posts.blacklist(['blacklist, of course.'])
if (filtered.length === 0) {
const notfoundEmbed = new Discord.MessageEmbed()
.setDescription("embed cut to preserve space")
message.channel.send(notfoundEmbed)
}
...
try {
headers = (await fetch(filtered.fileUrl, {
method: 'HEAD'
})).headers
}
Related
So i tried following the https://discordjs.guide/additional-info/rest-api.html guide before making my own. But I can't get either to work.
Firstly with /cat it crashes and the console returns with:
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at getJSONResponse (BOTLOCATION\index.js:77:14)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Client.<anonymous> (BOTLOCATION\index.js:90:20)
And /urban works but no matter what term I enter it returns with NULL.
Here is the code, its nearly identical from the guides apart from the added SlashCommandBuilder and REST.
const { request } = require('undici');
const clientId = 'CLIENTID_HERE';
const guildId = 'GUILDID_HERE';
const { SlashCommandBuilder } = require('#discordjs/builders');
const { REST } = require('#discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const commands = [
new SlashCommandBuilder().setName('cat').setDescription('Cat thing idk'),
new SlashCommandBuilder().setName('urban').setDescription('Urban Dictionary Thing'),
]
.map(command => command.toJSON());
const rest = new REST({ version: '9' }).setToken("TOKEN_HERE");
rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: commands })
//rest.put(Routes.applicationGuildCommands(clientId), { body: commands })
.then(() => console.log('Successfully registered application commands.'))
.catch(console.error);
const trim = (str, max) => (str.length > max ? `${str.slice(0, max - 3)}...` : str);
async function getJSONResponse(body) {
let fullBody = '';
for await (const data of body) {
fullBody += data.toString();
}
return JSON.parse(fullBody);
}
client.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return;
const { commandName } = interaction;
await interaction.deferReply();
if (commandName === 'cat') {
const catResult = await request('https://aws.random.cat/meow');
const { file } = await getJSONResponse(catResult.body);
interaction.reply({ files: [{ attachment: file, name: 'cat.png' }] });
} else if (commandName === 'urban') {
const term = interaction.options.getString('term');
const query = new URLSearchParams({ term });
const dictResult = await request(`https://api.urbandictionary.com/v0/define?${query}`);
const { list } = await getJSONResponse(dictResult.body);
if (!list.length) {
return interaction.editReply(`No results found for **${term}**.`);
}
const [answer] = list;
const embed = new MessageEmbed()
.setColor('#EFFF00')
.setTitle(answer.word)
.setURL(answer.permalink)
.addFields(
{ name: 'Definition', value: trim(answer.definition, 1024) },
{ name: 'Example', value: trim(answer.example, 1024) },
{
name: 'Rating',
value: `${answer.thumbs_up} thumbs up. ${answer.thumbs_down} thumbs down.`,
},
);
interaction.editReply({ embeds: [embed] });
}
});
So for the cat command since there is a deferReply first we need to use editReply since deferReply counts as the first/initial reply.
await interaction.deferReply();
const catResult = await request('https://aws.random.cat/meow').catch((err) => { console.log(err); });;
const { file } = await getJSONResponse(catResult.body).catch((err) => { console.log(err); });
return await interaction.editReply({ files: [{ attachment: file, name: 'cat.png' }] });
I also added a .catch to the end of each await, this was just for testing however I recommend it.
Now with the urban command, the reason it is using null is since you don't have the string option's text. We can check for it by adding an if statement.
await interaction.deferReply();
const term = interaction.options.getString('term');
if (!term) return await interaction.editReply('Please provide a term.'); // We need to add this check to see if the user provided the term option or not.
const query = new URLSearchParams({ term });
const dictResult = await request(`https://api.urbandictionary.com/v0/define?${query}`);
const { list } = await getJSONResponse(dictResult.body);
if (!list.length) {
return interaction.editReply(`No results found for **${term}**.`);
}
const [answer] = list;
const embed = new MessageEmbed()
.setColor('#EFFF00')
.setTitle(answer.word)
.setURL(answer.permalink)
.addFields(
{ name: 'Definition', value: trim(answer.definition, 1024) },
{ name: 'Example', value: trim(answer.example, 1024) },
{
name: 'Rating',
value: `${answer.thumbs_up} thumbs up. ${answer.thumbs_down} thumbs down.`,
},
);
return await interaction.editReply({ embeds: [embed] });
IMPORTANT: When you are building your slash command you are not setting a string option. In the commands array, when creating the second slash command called urban we will add the support for the string option there. (An example using the string option, discord.js guide all command options)
This is how we can do this:
const commands = [
new SlashCommandBuilder().setName('cat')
.setDescription('Cat thing idk'),
new SlashCommandBuilder()
.setName('urban')
.setDescription('Urban Dictionary Thing')
.addStringOption((option) => option.setName('term').setDescription('term')) // We first add the string option then set the name to 'term' which is what the code calls for and then the description.
].map((command) => command.toJSON());
If you would like to make the term input required, add .setRequired(true) which will not allow the command to be ran without entering the term to search.
Once you do that you should be all good! Tested the code and it's working once that's fixed
I have another question concerning my catch cmd. If I wanted to make it so that it was no longer an activable command but instead had a small chance of triggering when anyone speaks ever, how would I go about that? Would I need to put it in my message.js file? I know if I put it there as is it will trigger every time someone uses a command. However, I don't want it limited to someone using a command and I don't want it to happen every time. I've also heard of putting it in a separate json file and linking it back somehow. Any help is appreciated.
const profileModel = require("../models/profileSchema");
module.exports = {
name: "catch",
description: "users must type catch first to catch the animal",
async execute(client, message, msg, args, cmd, Discord, profileData) {
const prey = [
"rabbit",
"rat",
"bird",
];
const caught = [
"catch",
];
const chosenPrey = prey.sort(() => Math.random() - Math.random()).slice(0, 1);
const whenCaught = caught.sort(() => Math.random() - Math.random()).slice(0, 1);
const filter = ({ content }) => whenCaught.some((caught) => caught.toLowerCase() == content.toLowerCase());
const collector = message.channel.createMessageCollector({ max: 1, filter, time: 15000 });
const earnings = Math.floor(Math.random() * (20 - 5 + 1)) + 5;
collector.on('collect', async (m) => {
if(m.content?.toLowerCase() === 'catch') {
const user = m.author;
const userData = await profileModel.findOne({ userID: user.id });
message.channel.send(`${userData.name} caught the ${chosenPrey}! You gained ${earnings} coins.`);
}
await profileModel.findOneAndUpdate(
{
userID: m.author.id,
},
{
$inc: {
coins: earnings,
},
}
);
});
collector.on('end', (collected, reason) => {
if (reason == "time") {
message.channel.send('Too slow');
}
});
message.channel.send(`Look out, a ${chosenPrey}! Type CATCH before it gets away!`);
}
}
message.js file just in case
const profileModel = require("../../models/profileSchema");
const cooldowns = new Map();
module.exports = async (Discord, client, message) => {
let profileData;
try {
profileData = await profileModel.findOne({ userID: message.author.id });
if(!profileData){
let profile = await profileModel.create({
name: message.member.user.tag,
userID: message.author.id,
serverID: message.guild.id,
coins: 0,
});
profile.save();
}
} catch (err) {
console.log(err);
}
const prefix = '-';
if(!message.content.startsWith(prefix) || message.author.bot) return;
const args = message.content.slice(prefix.length).split(/ +/);
const cmd = args.shift().toLowerCase();
const command = client.commands.get(cmd) || client.commands.find(a => a.aliases && a.aliases.includes(cmd));
if(!command) return;
if(!cooldowns.has(command.name)){
cooldowns.set(command.name, new Discord.Collection());
}
const current_time = Date.now();
const time_stamps = cooldowns.get(command.name);
const cooldown_amount = (command.cooldown) * 1000;
if(time_stamps.has(message.author.id)){
const expiration_time = time_stamps.get(message.author.id) + cooldown_amount;
if(current_time < expiration_time){
const time_left = (expiration_time - current_time) / 1000;
return message.reply(`Slow down there! You have to wait ${time_left.toFixed(0)} seconds before you can perform ${command.name} again.`);
}
}
if(command) command.execute(client, message, args, cmd, Discord, profileData);
}
Yes...that can be possible. In your command handler, create and export a variable with a boolean
Make sure to do this in global scope (outside any function)
let canBeActivated = true;
module.exports.getCanBeActivated = function () { return canBeActivated };
module.exports.setCanBeActivated = function(value) { canBeActivated = value };
Then, in your command file, import it and check whether it can be activated
const { getCanBeActivated, setCanBeActivated } = require("path/to/message.js")
module.exports = {
...
execute(...) {
// command wont run
if(!getCanBeActivated()) return
}
You can make some logic to make the command run if canBeActivated is false (like get a random number between 1-100 and if it matches 4 run it).In case you need to change it, just run, setCanBeActivated
So I am trying to make a suggestion command using discord buttons in Discord.JS. When I run the command the embed and the buttons send but whenever I click one of the buttons whether it be Upvote, Maybe, or Downvote it edits the embed, but it never updates the number. I've tried upvote_number ++ and upvote_number + 1 but it doesn't work. It would be awesome if somebody could help me with this. Thank you.
const Discord = require('discord.js');
const disbut = require('discord-buttons');
const { MessageActionRow, MessageButton } = require("discord-buttons");
const { Color, Prefix } = require("../../config.js");
const { MessageEmbed } = require("discord.js");
const disbutpages = require("discord-embeds-pages-buttons")
const db = require('quick.db');
module.exports = {
name: "suggest",
aliases: [],
description: "Suggestion Command",
usage: "^suggest <suggestion>",
run: async(client, message, args) => {
const SayMessage = message.content.slice(8).trim();
let upvote_number = 0
let downvote_number = 0
let maybe_number = 0
const embed = new Discord.MessageEmbed()
.setAuthor("Suggestion from: " + message.author.tag, message.author.displayAvatarURL({dynamic: true}))
.setThumbnail(message.author.displayAvatarURL({dynamic: true}))
.setDescription(SayMessage)
.addField(`Votes`, `Upvote: **${upvote_number}**
Downvote: **${downvote_number}**`)
let upvotebutton = new MessageButton()
.setLabel(`Upvote`)
.setID(`upvote`)
.setEmoji(`⬆️`)
.setStyle("green")
let maybebutton = new MessageButton()
.setLabel(`Maybe`)
.setID(`maybe`)
.setEmoji(`🤷`)
.setStyle("blurple")
let downvotebutton = new MessageButton()
.setLabel(`Downvote`)
.setID(`downvote`)
.setEmoji(`⬇️`)
.setStyle("red")
let row = new MessageActionRow()
.addComponents(upvotebutton, maybebutton, downvotebutton)
const MESSAGE = await message.channel.send(embed, { components: [row] })
const filter = ( button ) => button.clicker.user.id === message.author.id
const collector = MESSAGE.createButtonCollector(filter, { time : 120000 });
collector.on('collect', async (b) => {
if(b.id == "upvote") {
await upvote_number + 1
await MESSAGE.edit(embed, { components: [row] });
await b.reply.defer()
}
if(b.id == "downvote") {
downvote_number + 1
MESSAGE.edit(embed, { components: [row] });
await b.reply.defer()
}
if(b.id == "maybe") {
maybe_number + 1
MESSAGE.edit(embed, { components: [row] });
await b.reply.defer()
}
})
collector.on('end', (b) => {
})
}
};
You'd want to use the += operator for your question. By the way, because of how button collectors work, the suggestions will be timing out after some time, which may cause you some issues in the future, so you may want to switch to the event. My only other concerns are that you are using d.js 12 and discord-buttons which are both deprecated. As d.js 12 is losing support soon because of discord's api updates, I'd highly recommend switching to v13, as it has built in buttons, along with many other new features such as menus and slash commands.
let upvote_number = 0
let downvote_number = 0
let maybe_number = 0
/* ... */
collector.on('collect', async b => {
if(b.id == "upvote") {
upvote_number += 1
updateEmbed()
await MESSAGE.edit(embed, { components: [row] })
await b.reply.defer()
} else if (b.id == "downvote") {
downvote_number += 1
updateEmbed()
await MESSAGE.edit(embed, { components: [row] })
await b.reply.defer()
} else if (b.id == "maybe") {
maybe_number += 1
updateEmbed()
await MESSAGE.edit(embed, { components: [row] })
await b.reply.defer()
}
});
updateEmbed(){
embed.fields.find(i=>i.name==='Votes').value = `Upvote: **${upvote_number}**
Downvote: **${downvote_number}**`
}
tldr: Use += to set vars dynamically as well as update the embed object, and update to `discord.js#latest`
I am trying to send an embed whenever a invite is created.
Channel set file
let config = require("../config.json");
const { MessageEmbed } = require("discord.js");
const Discord = require("discord.js");
const client = new Discord.Client();
module.exports = {
name: "setinvite",
description: "set invite channel log.",
async execute(message, args) {
if (!message.member.hasPermission(`ADMINISTRATOR`)) {
return message.channel.send(
`:x: You do not have permission to use this command!`
);
} else {
let channelx =
message.mentions.channels.first() ||
message.guild.channels.cache.find((c) => c.id === args[0]);
if (!channelx)
return message.channel.send(
`:x: Please specify a channel to make it as the modlogs!`
);
message.channel.send(`${channelx} has been set!`);
}
},
};
Index.js Modules (PS: I took the most relevant ones.)
const Discord = require("discord.js");
const client = new Discord.Client();
const fs = require("fs");
const { MessageEmbed } = require("discord.js");
const guildInvites = new Map();
const { channelx } = require("./commands/setinvite");
Index.js file
client.on("inviteCreate, message", async (invite) => {
const setc = client.channels.cache.get(`${channelx}`);
message.guild.fetchInvites().then((invites) => {
let allInvites = invites.map((i) => ({
name: "Invite",
value: `**Inviter:** ${i.inviter}
**Code:** https://discord.gg/${i.code}
**Usages:** ${i.uses} of ${i.maxUses === 0 ? "∞" : i.maxUses}
**Expires on:** ${
i.maxAge
? new Date(i.createdTimestamp + i.maxAge * 1000).toLocaleString()
: "never"
}`,
inline: true,
}));
setc.send(new Discord.MessageEmbed().addFields(allInvites));
});
});
I don't think the two events (inviteCreate, message) belong I did it because I received a error:
ReferenceError: message is not defined
Now, the channel set features works as intended but whenever the invite is created the embed doesn't send.
You can't merge all events inside one function.
You only need to keep the inviteCreate event. Then, you have to find a way to get the guild without using the "message" variable. Instead you can use the "invite" parameter that is present inside the inviteCreate event.
client.on("inviteCreate", async (invite) => {
const setc = client.channels.cache.get(`${channelx}`);
invite.guild.fetchInvites().then((invites) => {
let allInvites = invites.map((i) => ({
name: "Invite",
value: `**Inviter:** ${i.inviter}
**Code:** https://discord.gg/${i.code}
**Usages:** ${i.uses} of ${i.maxUses === 0 ? "∞" : i.maxUses}
**Expires on:** ${
i.maxAge
? new Date(i.createdTimestamp + i.maxAge * 1000).toLocaleString()
: "never"
}`,
inline: true,
}));
setc.send(new Discord.MessageEmbed().addFields(allInvites));
});
});
So I am making a Discord bot and I have a meme command that gets memes from r/memes, however sometimes it gives a meme and sometimes the code crashes and gives this error in console:
TypeError: Cannot read property 'data' of undefined
I'm not too sure what it could be so if anyone could help me out that would help a lot.
Here's my !meme command code:
const https = require('https');
const Discord = require('discord.js');
const url = 'https://www.reddit.com/r/memes/hot/.json'
module.exports = {
name: 'meme',
description: 'sends meme',
execute(message, args) {
https.get(url, (result) => {
var body = ''
result.on('data', (chunk) => {
body += chunk
})
result.on('end', () => {
var response = JSON.parse(body)
var index = response.data.children[Math.floor(Math.random() * 99) + 1].data
if (index.post_hint !== 'image') {
var text = index.selftext
const textembed = new Discord.MessageEmbed()
.setTitle(subRedditName)
.setColor(4388341)
.setDescription(`[${title}](${link})\n\n${text}`)
.setURL(`https://reddit.com/${subRedditName}`)
message.channel.send(textembed)
}
var image = index.preview.images[0].source.url.replace('&', '&')
var title = index.title
var link = 'https://reddit.com' + index.permalink
var subRedditName = index.subreddit_name_prefixed
if (index.post_hint !== 'image') {
const textembed = new Discord.MessageEmbed()
.setTitle(subRedditName)
.setColor(4388341)
.setDescription(`[${title}](${link})\n\n${text}`)
.setURL(`https://reddit.com/${subRedditName}`)
message.channel.send(textembed)
}
console.log(image);
const imageembed = new Discord.MessageEmbed()
.setTitle(subRedditName)
.setImage(image)
.setColor(4388341)
.setDescription(`[${title}](${link})`)
.setURL(`https://reddit.com/${subRedditName}`)
message.channel.send(imageembed)
}).on('error', function (e) {
console.log('Got an error: ', e)
})
})
},
}
It's because you're setting a hardcoded number (99) to get a random element from the response.data.children array. I've just checked the length of that array and it was 26. If your random number will be larger than that (and there is as you're generating a random number between 1 and 100), response.data.children[randomNumber] will be undefined.
Try to use the array's length as the max number instead so it will never be more than the number of elements:
let index =
response.data.children[
Math.floor(Math.random() * response.data.children.length)
].data;
The full code:
module.exports = {
name: 'meme',
description: 'sends meme',
execute(message, args) {
https.get(url, (result) => {
let body = '';
result.on('data', (chunk) => {
body += chunk;
});
result
.on('end', () => {
const response = JSON.parse(body);
const index =
response.data.children[
Math.floor(Math.random() * response.data.children.length)
].data;
const image = index.preview.images[0].source.url.replace(
'&',
'&',
);
const title = index.title;
const link = 'https://reddit.com' + index.permalink;
const subRedditName = index.subreddit_name_prefixed;
if (index.post_hint !== 'image') {
const text = index.selftext;
const textembed = new Discord.MessageEmbed()
.setTitle(subRedditName)
.setColor(4388341)
.setDescription(`[${title}](${link})\n\n${text}`)
.setURL(`https://reddit.com/${subRedditName}`);
message.channel.send(textembed);
}
const imageembed = new Discord.MessageEmbed()
.setTitle(subRedditName)
.setImage(image)
.setColor(4388341)
.setDescription(`[${title}](${link})`)
.setURL(`https://reddit.com/${subRedditName}`);
message.channel.send(imageembed);
})
.on('error', function (e) {
console.log('Got an error: ', e);
});
});
},
};