I am trying to forward messages sent to my bot via DM.
Everything works, except sending the stickers.
Every time I try to send the a message with a sticker, I just get an Error DiscordAPIError: Cannot use this sticker.
This is part my code:
let userMessage = new discord.MessageEmbed().setDescription(message.content || "")
let messageAttachment =
message.attachments.size > 0 ? message.attachments.first().url : null
userMessage.setImage(messageAttachment)
let messagePayload = {
content: null,
embeds: [],
stickers: null
}
messagePayload.content = `User <#${message.author.id}> said:`
messagePayload.embeds.push(userMessage)
messagePayload.stickers = message.stickers?.size > 0 ? [message.stickers.first()] : null
client.users.fetch(config.ids.me, false).then((user) => {
user.send(messagePayload)
})
and the messagePayload looks like this:
{
content: 'User <#USERID> said:',
embeds: [
MessageEmbed {
type: 'rich',
title: null,
description: '',
url: null,
color: null,
timestamp: null,
fields: [],
thumbnail: null,
image: [Object],
video: null,
author: null,
provider: null,
footer: null
}
],
stickers: [
Sticker {
id: '749054660769218631',
description: null,
type: null,
format: 'LOTTIE',
name: 'Wave',
packId: null,
tags: null,
available: null,
guildId: null,
user: null,
sortValue: null
}
]
}
In the Docs about sending stickers, it just says it has to be an Array either a Sticker-Object or a Snowflake. Since I am fetching the sticker Object, I assumed that just grabbing it and passing it into my messagePayload would do the job, but somehow the API does not accept it.
discord.Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS, is set, but it does not work with standard stickers aswell (e.g. messagePayload above)
As it turns out, you can only send stickers from a guild, inside that same guild.
See Github Issue.
Related
Using discord.js: "^14.5.0"
Trying to build an attendance tracker bot for discord that runs on a slash command. When the command is called it will check for which members are connected to a voice channel within the guild the command has been called.
*edit
The GatewayIntentBits I'm currently using
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildVoiceStates,
],
});
*edit
Currently I've found two methods to try this with
1.
const takeAttendance = async (interaction) => {
const allDiscordMembers = await interaction.guild.members.fetch({
force: true,
});
allDiscordMembers.forEach((member) => {
if (member.voice.channel !== null) {
console.log(member.voice.channel);
}
});
This returns the data I'm looking for (if you're familiar with Discord.js one of the properties with this code instance is: name: 'the channels name'), however; when the function is run another time and a member has moved to a new voice channel the data returned is the same (name: 'the old channels name', and not name: 'the current channels name') it will also not update if someone else joins the voice channel after the function has run for the first time.
or
2.
const takeAttendance = async (interaction) => {
const allChannels = await interaction.guild.channels.fetch();
const voiceChannels = allChannels.filter((channel) => channel.type === 2);
const membersInVoiceChannels = voiceChannels.map((channel) =>
channel.members.size > 0
? channel.members.map((member) => {
return `Attending:
Discord Nickname: ${member.nickname},
Username: ${member.user.username}, ${member.user.discriminator},
DiscordID: ${member.user.id},
Channel: ${channel.name},
Role: ${member.roles.cache.map((role) => role.name)}`;
})
: `No one is in ${channel.name} voice channel`
);
console.log("membersInVoiceChannels: ", membersInVoiceChannels);
};
This also returns the data I'm trying to capture, however; the issues is the same if the function is run a second time instead of getting the current channel it returns the old channel the member was in or if a new member joins a channel the information will not be updated and leaves the impression no one has joined.
This leads me to believe that the information being checked after the first call of the function is cached information and I'm looking for how I would go about doing this with the most recent information on the discord server.
Results:
expected: Both results are as expected
unexpected: When function is called a second time the results are identical
function logs
VoiceChannel {
type: 2,
guild: <ref *1> Guild {
id: '1024709322460123227',
name: 'HTCTH-Bot-Testing-Server',
icon: null,
features: [ 'APPLICATION_COMMAND_PERMISSIONS_V2' ],
commands: GuildApplicationCommandManager {
permissions: [ApplicationCommandPermissionsManager],
guild: [Circular *1]
},
members: GuildMemberManager { guild: [Circular *1] },
channels: GuildChannelManager { guild: [Circular *1] },
bans: GuildBanManager { guild: [Circular *1] },
roles: RoleManager { guild: [Circular *1] },
presences: PresenceManager {},
voiceStates: VoiceStateManager { guild: [Circular *1] },
stageInstances: StageInstanceManager { guild: [Circular *1] },
invites: GuildInviteManager { guild: [Circular *1] },
scheduledEvents: GuildScheduledEventManager { guild: [Circular *1] },
available: true,
shardId: 0,
splash: null,
banner: null,
description: null,
verificationLevel: 0,
vanityURLCode: null,
nsfwLevel: 0,
premiumSubscriptionCount: 0,
discoverySplash: null,
memberCount: redacted,
large: false,
premiumProgressBarEnabled: false,
applicationId: null,
afkTimeout: 300,
afkChannelId: null,
systemChannelId: null,
premiumTier: 0,
widgetEnabled: null,
widgetChannelId: null,
explicitContentFilter: 0,
mfaLevel: 0,
joinedTimestamp: redacted,
defaultMessageNotifications: 0,
systemChannelFlags: SystemChannelFlagsBitField { bitfield: 0 },
maximumMembers: 500000,
maximumPresences: null,
maxVideoChannelUsers: 25,
approximateMemberCount: null,
approximatePresenceCount: null,
vanityURLUses: null,
rulesChannelId: null,
publicUpdatesChannelId: null,
preferredLocale: 'en-US',
ownerId: '1024708192611074148',
emojis: GuildEmojiManager { guild: [Circular *1] },
stickers: GuildStickerManager { guild: [Circular *1] }
},
guildId: 'redacted',
parentId: 'redacted',
permissionOverwrites: PermissionOverwriteManager { channel: [Circular *2] },
messages: MessageManager { channel: [Circular *2] },
nsfw: false,
flags: ChannelFlagsBitField { bitfield: 0 },
id: 'redacted',
name: 'Team 4 a',
rawPosition: 26,
rtcRegion: null,
bitrate: 64000,
userLimit: 0,
videoQualityMode: null,
lastMessageId: null,
rateLimitPerUser: 0
}
function logs
'No one is in Team 1 a voice channel',
[
'Attending:\n' +
' Discord Nickname: redacted,\n' +
' Username: redacted,\n' +
' DiscordID: redacted,\n' +
' Channel: Team 1 b,\n' +
' Role: redactedn' +
' '
],
[
'Attending:\n' +
' Discord Nickname: redacted,\n' +
' Username:redacted,\n' +
' DiscordID: redacted,\n' +
' Channel: Team 1 c,\n' +
' Role: redacted\n' +
' '
],
'No one is in Team 1 d voice channel',
So I'm trying to make a bot using DiscordJS here.
I am currently trying to display user details. When I get the details, I'm not sure how to fetch specific details.
So I'm getting a user by doing
const user = await utils.findUser(message, args[0]);
Now here I get a user based on whatever the user entered in args.
The user variable looks something like this:
Collection [Map] {
'211975876747853825' => GuildMember {
guild: Guild {
members: [GuildMemberManager],
channels: [GuildChannelManager],
roles: [RoleManager],
presences: [PresenceManager],
voiceStates: [VoiceStateManager],
deleted: false,
available: true,
shardID: 0,
name: 'Elchea Kingdom',
icon: 'cd8156aed6c8ebc482df2252936afcee',
splash: null,
region: 'eu-west',
large: false,
features: [],
applicationID: null,
afkTimeout: 300,
embedEnabled: undefined,
premiumTier: 0,
premiumSubscriptionCount: null,
verificationLevel: 'MEDIUM',
explicitContentFilter: 'DISABLED',
mfaLevel: 0,
defaultMessageNotifications: 'MENTIONS',
systemChannelFlags: [SystemChannelFlags],
vanityURLCode: null,
description: null,
banner: null,
rulesChannelID: null,
publicUpdatesChannelID: null,
ownerID: '211975876747853825',
emojis: [GuildEmojiManager]
},
user: User {
bot: false,
discriminator: '0006',
avatar: '5ebd62928be9bd413a2b5f6e638587ea',
lastMessageID: null,
lastMessageChannelID: null,
flags: [UserFlags]
},
premiumSinceTimestamp: null,
deleted: false,
_roles: [
'600421802702929920',
'600737807664939008',
'603343858549391360',
'600425094598361091',
'600422841279578118',
'603314411243044875',
'617699524474830859',
'603316305495326740',
'617505016328224790',
'617449137767710743'
]
}
}
Now let's say I want to get get the Guild name which is "Elchea Kingdom". How could I do that? I have tried using Map.prototype.values() and iterate with it, but it doesn't work. I get an undefined value. I've tried doing stupid things such as user[0] and user.Guild to get guild information. But I always keep getting undefined value. What am I doing wrong, could you please guide me.
https://discord.js.org/#/docs/main/stable/class/Collection
You should call the variable users and then get member by .first()
const users = await utils.findUser(message, args[0]);
const member = users.first();
const user = member.user;
Which library are you using for the variable utils btw?
I read many posts on stackoverflow and other tutorial sites for writing object/JSON to a file, but none of the solutions worked for me.
1) Code:
let messages = await fetchMessages()
console.log(messages) // Prints an object
fs.writeFileSync('./msgdata.json', messages , 'utf-8');
2) Also tried,
fs.writeFileSync('./msgdata.json', JSON.stringify(messages) , 'utf-8');
3) Also tried,
fs.writeFile(), but get same output as above.
msgdata.json: (For 1)
[object Map]
msgdata.json: (For 2 & 3)
{}
Can someone please point out what could be causing this?
## Output of console.log(messages) ##
OUTPUT contains 10 more such objects having different id's:
channel:
TextChannel {
type: 'text',
id: '424825532274253312',
name: 'request',
position: 69,
parentID: '397363224286473987',
permissionOverwrites: [Object],
topic: null,
nsfw: false,
lastMessageID: '427143105410760704',
guild: [Object],
messages: [Object],
_typing: Map {} },
id: '427142596817846272',
type: 'DEFAULT',
content: '**Select your emoji:** __***Group 9:***__',
author:
ClientUser {
id: '407083773537350272',
username: 'Bot',
discriminator: '9256',
avatar: '9c374e719ba2ab4e69fd577005b635bf',
bot: true,
lastMessageID: null,
lastMessage: null,
verified: true,
email: null,
localPresence: {},
_typing: Map {},
friends: Collection {},
blocked: Collection {},
notes: Collection {},
premium: null,
mfaEnabled: false,
mobile: null,
settings: [Object],
guildSettings: Collection {} },
member:
GuildMember {
guild: [Object],
user: [Object],
_roles: [Array],
serverDeaf: false,
serverMute: false,
selfMute: undefined,
selfDeaf: undefined,
voiceSessionID: undefined,
voiceChannelID: undefined,
speaking: false,
nickname: null,
joinedTimestamp: 1517127343434,
lastMessageID: null,
lastMessage: null },
pinned: false,
tts: false,
nonce: undefined,
system: false,
embeds: [],
attachments: Collection {},
createdTimestamp: 1521909131007,
editedTimestamp: null,
reactions:
Collection {
'taillow:417281639777959940' => [Object],
'shroomish:417281639899463680' => [Object],
'sableye:417281640197521419' => [Object],
'ralts:417281642735075329' => [Object],
'sentret:417281644001624076' => [Object],
'shuppet:417281644291162132' => [Object],
'torchic:417281647210397706' => [Object],
'snubbull:417281647692480522' => [Object],
'sunkern:417281647763783681' => [Object],
'slowpoke:417281648653107200' => [Object],
'teddiursa:417281649537974273' => [Object],
'sneasel:417281649613471747' => [Object],
'snorunt:417281649819123712' => [Object],
'surskit:417281650163056640' => [Object],
'qwilfish:417281654629859348' => [Object],
'shelgon:417281654730522624' => [Object] },
mentions:
MessageMentions {
everyone: false,
users: Collection {},
roles: Collection {},
_content: '**Select your emoji:** __***Group
9:***__',
_client: [Object],
_guild: [Object],
_members: null,
_channels: null },
webhookID: null,
hit: null,
_edits: [] },
This is because the object returned is a Map object (MDN). When you JSON.strigify a Map object, it always returns {}. There are two ways to get readable JSON that stores your map. The first is to loop over all the entries and create a JSON (taking in consideration the keys and values). That should be simple to achieve.
Another way is to create an array from the Map and then stringify it.
fs.writeFileSync('./msgdata.json', JSON.stringify([...myObject]) , 'utf-8');
You can define Map.prototype.toJSON which works, but it isn't standard and is discouraged. It is automatically called by JSON.stringify if it finds it.
Map.prototype.toJSON = function() {return [...this];};
console.log(JSON.stringify(messages));
A better way is to define your own replacer function (and reviver function too if you need to reconstruct map from JSON). Here I also wrap the map representing array in a special object to tell maps and ordinary arrays apart in JSON:
function replacer (key, value) {
if (value instanceof Map) {
return {
_type: "map",
map: [...value],
}
} else return value;
}
function reviver (key, value) {
if (value._type == "map") return new Map(value.map);
else return value;
}
let str = JSON.stringify(messages, replacer);
let msg = JSON.parse(str, reviver);
The error you are getting about circular structure means that some objects/arrays there contain references to itself. When you store messages you don't need to store all the information related to the channels etc and instead only store ids. So that means extending replacer for TextChannels, ClientUsers, GuildMembers etc:
if (value instanceof TextChannel) {
return {
_type: "TextChannel",
id: value.id,
};
}
var util = require('util');
fs.writeFileSync('./data.json', util.inspect(obj) , 'utf-8');
Ref. Write objects into file with Node.js
I am trying to get the value of the 'text' key in a Json object that I get from a GET request to twitter via the twit library.
Im trying to use the filter function on the array because i wanna do functional programming.
I can use the json object inside a callback function on the T.get function:
const gotData = function(err, data, response) {
console.log(data)
}
T.get('search/tweets', params , gotData)
Then I want to filter only the value on the text key on each of the statuses, which is an array of objects
So i tried this:
let results = data.statuses.filter(
function(result){ return result.hasOwnProperty('text')
})
But I get back the same data.statuses back... ?
I want to get only the value of the text keys on the objects, what im I doing wrong ?
this is my whole code:
const Twit = require('twit')
const config = require('./config')
const T = new Twit(config)
let params = { q: 'drum', count: 2 }
const gotData = function(err, data, response) {
let results = data.statuses.filter(function(result){ return result.hasOwnProperty('text')})
console.log(results)
}
T.get('search/tweets', params , gotData)
And this a sample of the Json response i get, which corresponds to the data on the gotData function:
{ statuses:
[ { created_at: 'Sun May 07 11:35:16 +0000 2017',
id: 861182642888343600,
id_str: '861182642888343552',
text: '#was_going \nEvery hunk bore seven drums,\nEvery drum owned seven drums…',
truncated: false,
entities: [Object],
metadata: [Object],
source: 'Cheap Bots, Done Quick!',
in_reply_to_status_id: 861181362954489900,
in_reply_to_status_id_str: '861181362954489856',
in_reply_to_user_id: 795028044758949900,
in_reply_to_user_id_str: '795028044758949888',
in_reply_to_screen_name: 'was_going',
user: [Object],
geo: null,
coordinates: null,
place: null,
contributors: null,
is_quote_status: false,
retweet_count: 0,
favorite_count: 0,
favorited: false,
retweeted: false,
lang: 'en' },
{ created_at: 'Sun May 07 11:35:09 +0000 2017',
id: 861182610596405200,
id_str: '861182610596405248',
text: 'Would you rather have Data storage or A pedal assembly for a bass drum or high hat cymbals?',
truncated: false,
entities: [Object],
metadata: [Object],
source: 'Cheap Bots, Done Quick!',
in_reply_to_status_id: null,
in_reply_to_status_id_str: null,
in_reply_to_user_id: null,
in_reply_to_user_id_str: null,
in_reply_to_screen_name: null,
user: [Object],
geo: null,
coordinates: null,
place: null,
contributors: null,
is_quote_status: false,
retweet_count: 0,
favorite_count: 0,
favorited: false,
retweeted: false,
lang: 'en' } ],
search_metadata:
{ completed_in: 0.034,
max_id: 861182642888343600,
max_id_str: '861182642888343552',
next_results: '?max_id=861182610596405247&q=drum&count=2&include_entities=1',
query: 'drum',
refresh_url: '?since_id=861182642888343552&q=drum&include_entities=1',
count: 2,
since_id: 0,
since_id_str: '0' } }
You just check if theres a text property. You might also want to map it to that property:
let results = data.statuses.filter(
result=>result.hasOwnProperty('text')
).map(result=>result.text);
http://jsbin.com/niwezocuhu/edit?console
Or if you take care on performance ( O(n) instead of O(n+n*r)):
let results= data.statuses.reduce((arr,result)=>(result.text&&arr.push(result.text)&&false)||arr,[]);
I'm looking for a way to get data from this Collection.
The data looks like:
'0000000' => GuildMember {
guild:
Guild {
members: [Object],
id: '000000',
name: 'Zombie',
_rawVoiceStates: [Object] },
user:
User {
id: '0000000',
username: 'Orc',
_roles: [ '0000' ],
nickname: 'Orc',
joinedTimestamp: 00000,
lastMessageID: null },
'0000000' => GuildMember {
guild:
Guild {
members: [Object],
id: '000000',
name: 'Zombie',
_rawVoiceStates: [Object] },
user:
User {
id: '0000001',
username: 'Orc1',
_roles: [ '0000' ],
nickname: 'Orc',
joinedTimestamp: 00000,
lastMessageID: null },
_array: null,
_keyArray: null }
My current loop is:
var user;
for(var u in test.members){
user = test.members[u];
console.log("["+u+"] "+user.username);
}
It currently kicks back a TypeError: Cannot read property 'user' of null
I originally thought this the data was an array, but it's not according to the Discord.js docs, but I'm still not sure how to pull the username data from the collection.
Any help would be helpful.
Now i looked into the discord.js API and i think what u got todo is something like this (assuming test is your guild object):
test.members.forEach(function(guildMember, guildMemberId) {
console.log(guildMemberId, guildMember.user.username);
})
If that doesn't work try along the lines of:
var membersArray = test.members.array();
for(var guildMemberId in membersArray) {
console.log(guildMemberId, membersArray[guildMemberId].user.username);
}
TypeError: Cannot read property 'user' of null
means your user variable is null which means test.members[u] is null.
Try logging the test.members first and see if its filled.
user.user.username
is probably wrong. As it looks it should be just user.username