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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/lib/create.d.ts +35 -0
  3. package/lib/create.js +152 -0
  4. package/lib/index.d.ts +34 -0
  5. package/lib/index.js +240 -0
  6. package/lib/load.d.ts +30 -0
  7. package/lib/load.js +256 -0
  8. package/lib/types/AfkData.d.ts +4 -0
  9. package/lib/types/AfkData.js +2 -0
  10. package/lib/types/BackupData.d.ts +25 -0
  11. package/lib/types/BackupData.js +2 -0
  12. package/lib/types/BackupInfos.d.ts +6 -0
  13. package/lib/types/BackupInfos.js +2 -0
  14. package/lib/types/BanData.d.ts +5 -0
  15. package/lib/types/BanData.js +2 -0
  16. package/lib/types/BaseChannelData.d.ts +8 -0
  17. package/lib/types/BaseChannelData.js +2 -0
  18. package/lib/types/CategoryData.d.ts +6 -0
  19. package/lib/types/CategoryData.js +2 -0
  20. package/lib/types/ChannelPermissionData.d.ts +5 -0
  21. package/lib/types/ChannelPermissionData.js +2 -0
  22. package/lib/types/ChannelsData.d.ts +5 -0
  23. package/lib/types/ChannelsData.js +2 -0
  24. package/lib/types/CreateOptions.d.ts +9 -0
  25. package/lib/types/CreateOptions.js +2 -0
  26. package/lib/types/EmojiData.d.ts +5 -0
  27. package/lib/types/EmojiData.js +2 -0
  28. package/lib/types/LoadOptions.d.ts +6 -0
  29. package/lib/types/LoadOptions.js +2 -0
  30. package/lib/types/MemberData.d.ts +9 -0
  31. package/lib/types/MemberData.js +2 -0
  32. package/lib/types/MessageData.d.ts +10 -0
  33. package/lib/types/MessageData.js +2 -0
  34. package/lib/types/RoleData.d.ts +9 -0
  35. package/lib/types/RoleData.js +2 -0
  36. package/lib/types/TextChannelData.d.ts +10 -0
  37. package/lib/types/TextChannelData.js +2 -0
  38. package/lib/types/ThreadChannelData.d.ts +11 -0
  39. package/lib/types/ThreadChannelData.js +2 -0
  40. package/lib/types/VoiceChannelData.d.ts +5 -0
  41. package/lib/types/VoiceChannelData.js +2 -0
  42. package/lib/types/WidgetData.d.ts +4 -0
  43. package/lib/types/WidgetData.js +2 -0
  44. package/lib/types/index.d.ts +17 -0
  45. package/lib/types/index.js +33 -0
  46. package/lib/util.d.ts +27 -0
  47. package/lib/util.js +334 -0
  48. 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
+ }