discord-backup
Version:
A complete framework to facilitate server backup using discord.js v14 with rate limiting and error handling
210 lines (209 loc) • 8.33 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBans = getBans;
exports.getMembers = getMembers;
exports.getRoles = getRoles;
exports.getEmojis = getEmojis;
exports.getChannels = getChannels;
const discord_js_1 = require("discord.js");
const node_fetch_1 = require("node-fetch");
const util_1 = require("./util");
/**
* Returns an array with the banned members of the guild
* @param {Guild} guild The Discord guild
* @returns {Promise<BanData[]>} The banned members
*/
async function getBans(guild) {
const bans = [];
try {
const cases = await guild.bans.fetch({ limit: 1000 });
cases.forEach((ban) => {
bans.push({
id: ban.user.id,
reason: ban.reason || 'No reason provided'
});
});
}
catch (error) {
// Failed to fetch bans - continuing without them
}
return bans;
}
/**
* Returns an array with the members of the guild
* @param {Guild} guild The Discord guild
* @returns {Promise<MemberData>}
*/
async function getMembers(guild) {
const members = [];
try {
await guild.members.fetch({ limit: 1000 });
guild.members.cache.forEach((member) => {
if (member.user) {
members.push({
userId: member.user.id,
username: member.user.username,
discriminator: member.user.discriminator || '0',
avatarUrl: member.user.avatarURL(),
joinedTimestamp: member.joinedTimestamp,
roles: member.roles.cache.map((role) => role.id),
bot: member.user.bot
});
}
});
}
catch (error) {
// Failed to fetch members - falling back to cached members
guild.members.cache.forEach((member) => {
if (member.user) {
members.push({
userId: member.user.id,
username: member.user.username,
discriminator: member.user.discriminator || '0',
avatarUrl: member.user.avatarURL(),
joinedTimestamp: member.joinedTimestamp,
roles: member.roles.cache.map((role) => role.id),
bot: member.user.bot
});
}
});
}
return members;
}
/**
* Returns an array with the roles of the guild
* @param {Guild} guild The discord guild
* @returns {Promise<RoleData[]>} The roles of the guild
*/
async function getRoles(guild) {
const roles = [];
guild.roles.cache
.filter((role) => !role.managed)
.sort((a, b) => b.position - a.position)
.forEach((role) => {
const roleData = {
name: role.name,
color: role.hexColor,
hoist: role.hoist,
permissions: role.permissions.bitfield.toString(),
mentionable: role.mentionable,
position: role.position,
isEveryone: guild.id === role.id
};
roles.push(roleData);
});
return roles;
}
/**
* Returns an array with the emojis of the guild
* @param {Guild} guild The discord guild
* @param {CreateOptions} options The backup options
* @returns {Promise<EmojiData[]>} The emojis of the guild
*/
async function getEmojis(guild, options) {
const emojis = [];
try {
await guild.emojis.fetch();
await Promise.all(guild.emojis.cache.map(async (emoji) => {
try {
const eData = {
name: emoji.name || 'unknown'
};
if (options.saveImages && options.saveImages === 'base64') {
try {
const response = await (0, node_fetch_1.default)(emoji.imageURL());
const buffer = await response.buffer();
if (buffer.length <= 256 * 1024) {
eData.base64 = buffer.toString('base64');
}
else {
eData.url = emoji.imageURL();
}
}
catch {
eData.url = emoji.imageURL();
}
}
else {
eData.url = emoji.imageURL();
}
emojis.push(eData);
}
catch (error) {
// Failed to process emoji - skipping
}
}));
}
catch (error) {
// Failed to fetch emojis - falling back to cached emojis
guild.emojis.cache.forEach((emoji) => {
emojis.push({
name: emoji.name || 'unknown',
url: emoji.imageURL()
});
});
}
return emojis;
}
/**
* Returns an array with the channels of the guild
* @param {Guild} guild The discord guild
* @param {CreateOptions} options The backup options
* @returns {ChannelData[]} The channels of the guild
*/
async function getChannels(guild, options) {
return new Promise(async (resolve) => {
const channels = {
categories: [],
others: []
};
// Gets the list of the categories and sort them by position
const categories = guild.channels.cache.filter((ch) => ch.type === discord_js_1.ChannelType.GuildCategory)
.sort((a, b) => a.position - b.position)
.toJSON();
for (const category of categories) {
const categoryData = {
name: category.name, // The name of the category
permissions: (0, util_1.fetchChannelPermissions)(category), // The overwrite permissions of the category
children: [] // The children channels of the category
};
// Gets the children channels of the category and sort them by position
const children = category.children.cache.sort((a, b) => a.position - b.position).toJSON();
for (const child of children) {
// For each child channel
if (child.type === discord_js_1.ChannelType.GuildText || child.type === discord_js_1.ChannelType.GuildAnnouncement) {
const channelData = await (0, util_1.fetchTextChannelData)(child, options); // Gets the channel data
categoryData.children.push(channelData); // And then push the child in the categoryData
}
else {
const channelData = await (0, util_1.fetchVoiceChannelData)(child); // Gets the channel data
categoryData.children.push(channelData); // And then push the child in the categoryData
}
}
channels.categories.push(categoryData); // Update channels object
}
// Gets the list of the other channels (that are not in a category) and sort them by position
const others = guild.channels.cache.filter((ch) => {
return (!ch.parent &&
ch.type !== discord_js_1.ChannelType.GuildCategory &&
// && ch.type !== 'GUILD_STORE' // there is no way to restore store channels, ignore them
ch.type !== discord_js_1.ChannelType.AnnouncementThread &&
ch.type !== discord_js_1.ChannelType.PrivateThread &&
ch.type !== discord_js_1.ChannelType.PublicThread); // threads will be saved with fetchTextChannelData
})
.sort((a, b) => a.position - b.position)
.toJSON();
for (const channel of others) {
// For each channel
if (channel.type === discord_js_1.ChannelType.GuildText || channel.type === discord_js_1.ChannelType.GuildAnnouncement) {
const channelData = await (0, util_1.fetchTextChannelData)(channel, options); // Gets the channel data
channels.others.push(channelData); // Update channels object
}
else {
const channelData = await (0, util_1.fetchVoiceChannelData)(channel); // Gets the channel data
channels.others.push(channelData); // Update channels object
}
}
resolve(channels); // Returns the list of the channels
});
}