discord.js-backup-v13 13.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/lib/create.d.ts +35 -0
- package/lib/create.js +152 -0
- package/lib/index.d.ts +34 -0
- package/lib/index.js +240 -0
- package/lib/load.d.ts +30 -0
- package/lib/load.js +256 -0
- package/lib/types/AfkData.d.ts +4 -0
- package/lib/types/AfkData.js +2 -0
- package/lib/types/BackupData.d.ts +25 -0
- package/lib/types/BackupData.js +2 -0
- package/lib/types/BackupInfos.d.ts +6 -0
- package/lib/types/BackupInfos.js +2 -0
- package/lib/types/BanData.d.ts +5 -0
- package/lib/types/BanData.js +2 -0
- package/lib/types/BaseChannelData.d.ts +8 -0
- package/lib/types/BaseChannelData.js +2 -0
- package/lib/types/CategoryData.d.ts +6 -0
- package/lib/types/CategoryData.js +2 -0
- package/lib/types/ChannelPermissionData.d.ts +5 -0
- package/lib/types/ChannelPermissionData.js +2 -0
- package/lib/types/ChannelsData.d.ts +5 -0
- package/lib/types/ChannelsData.js +2 -0
- package/lib/types/CreateOptions.d.ts +9 -0
- package/lib/types/CreateOptions.js +2 -0
- package/lib/types/EmojiData.d.ts +5 -0
- package/lib/types/EmojiData.js +2 -0
- package/lib/types/LoadOptions.d.ts +6 -0
- package/lib/types/LoadOptions.js +2 -0
- package/lib/types/MemberData.d.ts +9 -0
- package/lib/types/MemberData.js +2 -0
- package/lib/types/MessageData.d.ts +10 -0
- package/lib/types/MessageData.js +2 -0
- package/lib/types/RoleData.d.ts +9 -0
- package/lib/types/RoleData.js +2 -0
- package/lib/types/TextChannelData.d.ts +10 -0
- package/lib/types/TextChannelData.js +2 -0
- package/lib/types/ThreadChannelData.d.ts +11 -0
- package/lib/types/ThreadChannelData.js +2 -0
- package/lib/types/VoiceChannelData.d.ts +5 -0
- package/lib/types/VoiceChannelData.js +2 -0
- package/lib/types/WidgetData.d.ts +4 -0
- package/lib/types/WidgetData.js +2 -0
- package/lib/types/index.d.ts +17 -0
- package/lib/types/index.js +33 -0
- package/lib/util.d.ts +27 -0
- package/lib/util.js +334 -0
- package/package.json +21 -0
package/lib/util.js
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clearGuild = exports.loadChannel = exports.loadCategory = exports.fetchTextChannelData = exports.fetchChannelMessages = exports.fetchVoiceChannelData = exports.fetchChannelPermissions = void 0;
|
|
4
|
+
const node_fetch_1 = require("node-fetch");
|
|
5
|
+
const MaxBitratePerTier = {
|
|
6
|
+
NONE: 64000,
|
|
7
|
+
TIER_1: 128000,
|
|
8
|
+
TIER_2: 256000,
|
|
9
|
+
TIER_3: 384000
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Gets the permissions for a channel
|
|
13
|
+
*/
|
|
14
|
+
function fetchChannelPermissions(channel) {
|
|
15
|
+
const permissions = [];
|
|
16
|
+
channel.permissionOverwrites?.cache
|
|
17
|
+
.filter((p) => p.type === 'role')
|
|
18
|
+
.forEach((perm) => {
|
|
19
|
+
const role = channel.guild.roles.cache.get(perm.id);
|
|
20
|
+
if (role) {
|
|
21
|
+
permissions.push({
|
|
22
|
+
roleName: role.name,
|
|
23
|
+
allow: perm.allow.bitfield.toString(),
|
|
24
|
+
deny: perm.deny.bitfield.toString()
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return permissions;
|
|
29
|
+
}
|
|
30
|
+
exports.fetchChannelPermissions = fetchChannelPermissions;
|
|
31
|
+
/**
|
|
32
|
+
* Fetches the voice channel data that is necessary for the backup
|
|
33
|
+
*/
|
|
34
|
+
async function fetchVoiceChannelData(channel) {
|
|
35
|
+
return new Promise(async (resolve) => {
|
|
36
|
+
const channelData = {
|
|
37
|
+
type: 'GUILD_VOICE',
|
|
38
|
+
name: channel.name,
|
|
39
|
+
bitrate: channel.bitrate,
|
|
40
|
+
userLimit: channel.userLimit,
|
|
41
|
+
parent: channel.parent ? channel.parent.name : null,
|
|
42
|
+
permissions: fetchChannelPermissions(channel)
|
|
43
|
+
};
|
|
44
|
+
/* Return channel data */
|
|
45
|
+
resolve(channelData);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
exports.fetchVoiceChannelData = fetchVoiceChannelData;
|
|
49
|
+
async function fetchChannelMessages(channel, options) {
|
|
50
|
+
let messages = [];
|
|
51
|
+
const messageCount = isNaN(options.maxMessagesPerChannel) ? 10 : options.maxMessagesPerChannel;
|
|
52
|
+
const fetchOptions = { limit: 100 };
|
|
53
|
+
let lastMessageId;
|
|
54
|
+
let fetchComplete = false;
|
|
55
|
+
while (!fetchComplete) {
|
|
56
|
+
if (lastMessageId) {
|
|
57
|
+
fetchOptions.before = lastMessageId;
|
|
58
|
+
}
|
|
59
|
+
const fetched = await channel.messages.fetch(fetchOptions);
|
|
60
|
+
if (fetched.size === 0) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
lastMessageId = fetched.last().id;
|
|
64
|
+
await Promise.all(fetched.map(async (msg) => {
|
|
65
|
+
if (!msg.author || messages.length >= messageCount) {
|
|
66
|
+
fetchComplete = true;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const files = await Promise.all(msg.attachments.map(async (a) => {
|
|
70
|
+
let attach = a.url;
|
|
71
|
+
if (a.url && ['png', 'jpg', 'jpeg', 'jpe', 'jif', 'jfif', 'jfi'].includes(a.url)) {
|
|
72
|
+
if (options.saveImages && options.saveImages === 'base64') {
|
|
73
|
+
attach = (await ((0, node_fetch_1.default)(a.url).then((res) => res.buffer()))).toString('base64');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
name: a.name,
|
|
78
|
+
attachment: attach
|
|
79
|
+
};
|
|
80
|
+
}));
|
|
81
|
+
messages.push({
|
|
82
|
+
username: msg.author.username,
|
|
83
|
+
avatar: msg.author.displayAvatarURL(),
|
|
84
|
+
content: msg.cleanContent,
|
|
85
|
+
embeds: msg.embeds,
|
|
86
|
+
files,
|
|
87
|
+
pinned: msg.pinned,
|
|
88
|
+
sentAt: msg.createdAt.toISOString(),
|
|
89
|
+
});
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
return messages;
|
|
93
|
+
}
|
|
94
|
+
exports.fetchChannelMessages = fetchChannelMessages;
|
|
95
|
+
/**
|
|
96
|
+
* Fetches the text channel data that is necessary for the backup
|
|
97
|
+
*/
|
|
98
|
+
async function fetchTextChannelData(channel, options) {
|
|
99
|
+
return new Promise(async (resolve) => {
|
|
100
|
+
const channelData = {
|
|
101
|
+
type: channel.type,
|
|
102
|
+
name: channel.name,
|
|
103
|
+
nsfw: channel.nsfw,
|
|
104
|
+
rateLimitPerUser: channel.type === 'GUILD_TEXT' ? channel.rateLimitPerUser : undefined,
|
|
105
|
+
parent: channel.parent ? channel.parent.name : null,
|
|
106
|
+
topic: channel.topic,
|
|
107
|
+
permissions: fetchChannelPermissions(channel),
|
|
108
|
+
messages: [],
|
|
109
|
+
isNews: channel.type === 'GUILD_NEWS',
|
|
110
|
+
rulesChannel: channel.guild.rulesChannelId == channel.id,
|
|
111
|
+
publicUpdatesChannel: channel.guild.publicUpdatesChannelId == channel.id,
|
|
112
|
+
threads: []
|
|
113
|
+
};
|
|
114
|
+
/* Fetch channel threads */
|
|
115
|
+
if (channel.threads.cache.size > 0) {
|
|
116
|
+
await Promise.all(channel.threads.cache.map(async (thread) => {
|
|
117
|
+
const threadData = {
|
|
118
|
+
type: thread.type,
|
|
119
|
+
name: thread.name,
|
|
120
|
+
archived: thread.archived,
|
|
121
|
+
autoArchiveDuration: thread.autoArchiveDuration,
|
|
122
|
+
locked: thread.locked,
|
|
123
|
+
rateLimitPerUser: thread.rateLimitPerUser,
|
|
124
|
+
messages: []
|
|
125
|
+
};
|
|
126
|
+
try {
|
|
127
|
+
threadData.messages = await fetchChannelMessages(thread, options);
|
|
128
|
+
/* Return thread data */
|
|
129
|
+
channelData.threads.push(threadData);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
channelData.threads.push(threadData);
|
|
133
|
+
}
|
|
134
|
+
}));
|
|
135
|
+
}
|
|
136
|
+
/* Fetch channel messages */
|
|
137
|
+
try {
|
|
138
|
+
channelData.messages = await fetchChannelMessages(channel, options);
|
|
139
|
+
/* Return channel data */
|
|
140
|
+
resolve(channelData);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
resolve(channelData);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
exports.fetchTextChannelData = fetchTextChannelData;
|
|
148
|
+
/**
|
|
149
|
+
* Creates a category for the guild
|
|
150
|
+
*/
|
|
151
|
+
async function loadCategory(categoryData, guild) {
|
|
152
|
+
return new Promise((resolve) => {
|
|
153
|
+
guild.channels.create(categoryData.name, {
|
|
154
|
+
type: 'GUILD_CATEGORY'
|
|
155
|
+
}).then(async (category) => {
|
|
156
|
+
const finalPermissions = [];
|
|
157
|
+
categoryData.permissions.forEach((perm) => {
|
|
158
|
+
const role = guild.roles.cache.find((r) => r.name === perm.roleName);
|
|
159
|
+
if (role) {
|
|
160
|
+
finalPermissions.push({
|
|
161
|
+
id: role.id,
|
|
162
|
+
allow: BigInt(perm.allow),
|
|
163
|
+
deny: BigInt(perm.deny)
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
await category.permissionOverwrites.set(finalPermissions);
|
|
168
|
+
resolve(category);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
exports.loadCategory = loadCategory;
|
|
173
|
+
/**
|
|
174
|
+
* Create a channel and returns it
|
|
175
|
+
*/
|
|
176
|
+
async function loadChannel(channelData, guild, category, options) {
|
|
177
|
+
return new Promise(async (resolve) => {
|
|
178
|
+
const loadMessages = (channel, messages, previousWebhook) => {
|
|
179
|
+
return new Promise(async (resolve) => {
|
|
180
|
+
const webhook = previousWebhook || await channel.createWebhook('MessagesBackup', {
|
|
181
|
+
avatar: channel.client.user.displayAvatarURL()
|
|
182
|
+
}).catch(() => { });
|
|
183
|
+
if (!webhook)
|
|
184
|
+
return resolve();
|
|
185
|
+
messages = messages
|
|
186
|
+
.filter((m) => m.content.length > 0 || m.embeds.length > 0 || m.files.length > 0)
|
|
187
|
+
.reverse();
|
|
188
|
+
messages = messages.slice(messages.length - options.maxMessagesPerChannel);
|
|
189
|
+
for (const msg of messages) {
|
|
190
|
+
const sentMsg = await webhook
|
|
191
|
+
.send({
|
|
192
|
+
content: msg.content.length ? msg.content : undefined,
|
|
193
|
+
username: msg.username,
|
|
194
|
+
avatarURL: msg.avatar,
|
|
195
|
+
embeds: msg.embeds,
|
|
196
|
+
files: msg.files,
|
|
197
|
+
allowedMentions: options.allowedMentions,
|
|
198
|
+
threadId: channel.isThread() ? channel.id : undefined
|
|
199
|
+
})
|
|
200
|
+
.catch((err) => {
|
|
201
|
+
console.log(err.message);
|
|
202
|
+
});
|
|
203
|
+
if (msg.pinned && sentMsg)
|
|
204
|
+
await sentMsg.pin();
|
|
205
|
+
}
|
|
206
|
+
resolve(webhook);
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
const createOptions = {
|
|
210
|
+
type: null,
|
|
211
|
+
parent: category
|
|
212
|
+
};
|
|
213
|
+
if (channelData.type === 'GUILD_TEXT' || channelData.type === 'GUILD_NEWS') {
|
|
214
|
+
createOptions.topic = channelData.topic;
|
|
215
|
+
createOptions.nsfw = channelData.nsfw;
|
|
216
|
+
createOptions.rateLimitPerUser = channelData.rateLimitPerUser;
|
|
217
|
+
createOptions.type =
|
|
218
|
+
channelData.isNews && guild.features.includes('NEWS') ? 'GUILD_NEWS' : 'GUILD_TEXT';
|
|
219
|
+
}
|
|
220
|
+
else if (channelData.type === 'GUILD_VOICE') {
|
|
221
|
+
let bitrate = channelData.bitrate;
|
|
222
|
+
const bitrates = Object.values(MaxBitratePerTier);
|
|
223
|
+
while (bitrate > MaxBitratePerTier[guild.premiumTier]) {
|
|
224
|
+
bitrate = bitrates[Object.keys(MaxBitratePerTier).indexOf(guild.premiumTier) - 1];
|
|
225
|
+
}
|
|
226
|
+
createOptions.bitrate = bitrate;
|
|
227
|
+
createOptions.userLimit = channelData.userLimit;
|
|
228
|
+
createOptions.type = 'GUILD_VOICE';
|
|
229
|
+
}
|
|
230
|
+
guild.channels.create(channelData.name, createOptions).then(async (channel) => {
|
|
231
|
+
/* Update channel permissions */
|
|
232
|
+
if (channelData.rulesChannel) {
|
|
233
|
+
try {
|
|
234
|
+
const oldRules = guild.rulesChannel
|
|
235
|
+
await guild.setRulesChannel(channel.id);
|
|
236
|
+
await guild.client.api.channels(oldRules.id).delete();
|
|
237
|
+
} catch {}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (channelData.publicUpdatesChannel) {
|
|
241
|
+
try {
|
|
242
|
+
const oldPublic = guild.publicUpdatesChannel
|
|
243
|
+
await guild.setPublicUpdatesChannel(channel.id);
|
|
244
|
+
await guild.client.api.channels(oldPublic.id).delete();
|
|
245
|
+
} catch {}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const finalPermissions = [];
|
|
249
|
+
channelData.permissions.forEach((perm) => {
|
|
250
|
+
const role = guild.roles.cache.find((r) => r.name === perm.roleName);
|
|
251
|
+
if (role) {
|
|
252
|
+
finalPermissions.push({
|
|
253
|
+
id: role.id,
|
|
254
|
+
allow: BigInt(perm.allow),
|
|
255
|
+
deny: BigInt(perm.deny)
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
await channel.permissionOverwrites.set(finalPermissions);
|
|
260
|
+
if (channelData.type === 'GUILD_TEXT') {
|
|
261
|
+
/* Load messages */
|
|
262
|
+
let webhook;
|
|
263
|
+
if (channelData.messages.length > 0) {
|
|
264
|
+
webhook = await loadMessages(channel, channelData.messages).catch(() => { });
|
|
265
|
+
}
|
|
266
|
+
/* Load threads */
|
|
267
|
+
if (channelData.threads.length > 0) { //&& guild.features.includes('THREADS_ENABLED')) {
|
|
268
|
+
await Promise.all(channelData.threads.map(async (threadData) => {
|
|
269
|
+
let autoArchiveDuration = threadData.autoArchiveDuration;
|
|
270
|
+
if (!guild.features.includes('SEVEN_DAY_THREAD_ARCHIVE') && autoArchiveDuration === 10080)
|
|
271
|
+
autoArchiveDuration = 4320;
|
|
272
|
+
if (!guild.features.includes('THREE_DAY_THREAD_ARCHIVE') && autoArchiveDuration === 4320)
|
|
273
|
+
autoArchiveDuration = 1440;
|
|
274
|
+
return channel.threads.create({
|
|
275
|
+
name: threadData.name,
|
|
276
|
+
autoArchiveDuration
|
|
277
|
+
}).then((thread) => {
|
|
278
|
+
if (!webhook)
|
|
279
|
+
return;
|
|
280
|
+
return loadMessages(thread, threadData.messages, webhook);
|
|
281
|
+
});
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
resolve(channel);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
resolve(channel);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
exports.loadChannel = loadChannel;
|
|
293
|
+
/**
|
|
294
|
+
* Delete all roles, all channels, all emojis, etc... of a guild
|
|
295
|
+
*/
|
|
296
|
+
async function clearGuild(guild) {
|
|
297
|
+
guild.roles.cache
|
|
298
|
+
.filter((role) => !role.managed && role.editable && role.id !== guild.id)
|
|
299
|
+
.forEach((role) => {
|
|
300
|
+
role.delete().catch(() => { });
|
|
301
|
+
});
|
|
302
|
+
guild.channels.cache.forEach((channel) => {
|
|
303
|
+
channel.delete().catch(() => { });
|
|
304
|
+
});
|
|
305
|
+
guild.emojis.cache.forEach((emoji) => {
|
|
306
|
+
emoji.delete().catch(() => { });
|
|
307
|
+
});
|
|
308
|
+
const webhooks = await guild.fetchWebhooks().catch(() => null);
|
|
309
|
+
if (webhooks) webhooks.forEach((webhook) => {
|
|
310
|
+
webhook.delete().catch(() => { });
|
|
311
|
+
});
|
|
312
|
+
const bans = await guild.bans.fetch({ limit: 99 });
|
|
313
|
+
bans.forEach((ban) => {
|
|
314
|
+
guild.members.unban(ban.user).catch(() => { });
|
|
315
|
+
});
|
|
316
|
+
guild.setAFKChannel(null);
|
|
317
|
+
guild.setAFKTimeout(60 * 5);
|
|
318
|
+
guild.setIcon(null);
|
|
319
|
+
guild.setBanner(null).catch(() => { });
|
|
320
|
+
guild.setSplash(null).catch(() => { });
|
|
321
|
+
guild.setDefaultMessageNotifications('ONLY_MENTIONS');
|
|
322
|
+
guild.setWidgetSettings({
|
|
323
|
+
enabled: false,
|
|
324
|
+
channel: null
|
|
325
|
+
});
|
|
326
|
+
if (!guild.features.includes('COMMUNITY')) {
|
|
327
|
+
guild.setExplicitContentFilter('DISABLED');
|
|
328
|
+
guild.setVerificationLevel('NONE');
|
|
329
|
+
}
|
|
330
|
+
guild.setSystemChannel(null);
|
|
331
|
+
guild.setSystemChannelFlags(['SUPPRESS_GUILD_REMINDER_NOTIFICATIONS', 'SUPPRESS_JOIN_NOTIFICATIONS', 'SUPPRESS_PREMIUM_SUBSCRIPTIONS']);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
exports.clearGuild = clearGuild;
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "discord.js-backup-v13",
|
|
3
|
+
"version": "13.1.1",
|
|
4
|
+
"main": "lib/index.js",
|
|
5
|
+
"files": [
|
|
6
|
+
"lib/**/*"
|
|
7
|
+
],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
12
|
+
"lint": "tslint -p tsconfig.json"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"discord.js-selfbot-v13": "^3.0.0",
|
|
16
|
+
"node-fetch": "cjs"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"discord.js-selfbot-v13": "^3.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|