UNPKG

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
"use strict"; 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 }); }