├── .gitignore
├── package.json
├── .github
└── workflows
│ └── server-cloner.yml
├── README.md
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .env
3 | .vscode/
4 | .idea/
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "discord-server-cloner",
3 | "version": "1.0.0",
4 | "description": "A Discord selfbot tool to clone entire servers with emoji support and access control",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [
11 | "discord",
12 | "selfbot",
13 | "server",
14 | "clone",
15 | "emoji"
16 | ],
17 | "author": "Manish",
18 | "license": "MIT",
19 | "dependencies": {
20 | "discord.js-selfbot-v13": "^3.7.0",
21 | "dotenv": "^17.2.2"
22 | }
23 | }
--------------------------------------------------------------------------------
/.github/workflows/server-cloner.yml:
--------------------------------------------------------------------------------
1 | name: Discord Server Cloner Bot
2 |
3 | on:
4 | workflow_dispatch: # Sirf manually trigger hoga
5 |
6 | jobs:
7 | run-bot:
8 | runs-on: ubuntu-latest
9 |
10 | steps:
11 | - name: Checkout code
12 | uses: actions/checkout@v3
13 |
14 | - name: Setup Node.js
15 | uses: actions/setup-node@v3
16 | with:
17 | node-version: '22'
18 | cache: 'npm'
19 |
20 | - name: Install dependencies
21 | run: npm ci
22 |
23 | - name: Run Server Cloner Bot
24 | env:
25 | TOKEN: ${{ secrets.DISCORD_TOKEN }}
26 | ALLOWED_USER_IDS: ${{ secrets.ALLOWED_USER_IDS }}
27 | run: |
28 | echo "🚀 Starting Discord Server Cloner Bot..."
29 | echo "🤖 Bot will now listen for !clone commands on Discord"
30 | node index.js
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | ## Features
17 |
18 | - Clone entire Discord servers with one command
19 | - Optional emoji cloning with rate limiting
20 | - Progress tracking in Discord chat
21 | - GitHub Actions integration
22 |
23 | ## Setup
24 |
25 | 1. **Fork this repository**
26 | 2. **Add your secrets in repository settings:**
27 | - `DISCORD_TOKEN` - Your Discord user token
28 | - `ALLOWED_USER_IDS` - Comma-separated list of allowed user IDs
29 |
30 | ## 🎯 Usage
31 |
32 | ### Discord Command
33 | ```
34 | !clone
35 | ```
36 |
37 | The bot will then ask for confirmation:
38 | 1. Confirm server details (y/n)
39 | 2. Choose whether to clone emojis (y/n)
40 |
41 | ### GitHub Actions
42 | 1. Go to the **Actions** tab
43 | 2. Select **Discord Server Cloner**
44 | 3. Click **Run workflow**
45 | ## ⚙️ Environment Variables if you want to run on your pc
46 |
47 | Create a `.env` file with:
48 |
49 | ```env
50 | TOKEN=your_discord_user_token_here
51 | ALLOWED_USER_IDS=user_id1,user_id2,user_id3
52 | ```
53 | ## ⚠️ Disclaimer
54 |
55 | This tool is for educational purposes only. Use responsibly and ensure you have permission to clone servers.
56 |
57 |
58 |
59 | ⚠️ If you are using this project or it's code anywhere, please give proper credit to it's Manish .
60 | Do not redistribute or sell this project without permission.
61 | Respect the original author!
62 |
63 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const { Client } = require('discord.js-selfbot-v13');
3 | const https = require('https');
4 |
5 | const colors = {
6 | red: '\x1b[31m',
7 | green: '\x1b[32m',
8 | yellow: '\x1b[33m',
9 | blue: '\x1b[34m',
10 | magenta: '\x1b[35m',
11 | cyan: '\x1b[36m',
12 | white: '\x1b[37m',
13 | reset: '\x1b[0m'
14 | };
15 |
16 | const log = {
17 | success: (msg) => console.log(`${colors.green}[+] ${msg}${colors.reset}`),
18 | error: (msg) => console.log(`${colors.red}[-] ${msg}${colors.reset}`),
19 | warning: (msg) => console.log(`${colors.yellow}[!] ${msg}${colors.reset}`),
20 | info: (msg) => console.log(`${colors.cyan}[i] ${msg}${colors.reset}`),
21 | header: (msg) => console.log(`${colors.magenta}${msg}${colors.reset}`)
22 | };
23 |
24 |
25 | const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
26 |
27 | async function downloadImage(url) {
28 | return new Promise((resolve, reject) => {
29 | https.get(url, (res) => {
30 | const chunks = [];
31 | res.on('data', chunk => chunks.push(chunk));
32 | res.on('end', () => {
33 | const buffer = Buffer.concat(chunks);
34 | const base64 = buffer.toString('base64');
35 | const mimeType = res.headers['content-type'] || 'image/png';
36 | resolve(`data:${mimeType};base64,${base64}`);
37 | });
38 | res.on('error', reject);
39 | }).on('error', reject);
40 | });
41 | }
42 |
43 | class ServerCloner {
44 | constructor(client) {
45 | this.client = client;
46 | this.roleMapping = new Map();
47 | this.stats = {
48 | rolesCreated: 0,
49 | categoriesCreated: 0,
50 | channelsCreated: 0,
51 | emojisCreated: 0,
52 | failed: 0
53 | };
54 | }
55 |
56 | async cloneServer(sourceGuildId, targetGuildId, cloneEmojis = true, progressChannel = null) {
57 | try {
58 | const sourceGuild = this.client.guilds.cache.get(sourceGuildId);
59 | const targetGuild = this.client.guilds.cache.get(targetGuildId);
60 |
61 | if (!sourceGuild) {
62 | throw new Error('Source server not found! Make sure you\'re a member.');
63 | }
64 |
65 | if (!targetGuild) {
66 | throw new Error('Target server not found! Make sure you\'re a member with admin permissions.');
67 | }
68 |
69 | this.sendProgress(`Cloning from: ${sourceGuild.name} -> ${targetGuild.name}`, progressChannel);
70 | this.sendProgress('Starting cloning process...', progressChannel);
71 |
72 |
73 | await this.deleteExistingContent(targetGuild, progressChannel);
74 |
75 |
76 | await this.cloneRoles(sourceGuild, targetGuild, progressChannel);
77 | await this.cloneCategories(sourceGuild, targetGuild, progressChannel);
78 | await this.cloneChannels(sourceGuild, targetGuild, progressChannel);
79 |
80 |
81 | if (cloneEmojis) {
82 | await this.cloneEmojis(sourceGuild, targetGuild, progressChannel);
83 | }
84 |
85 | await this.cloneServerInfo(sourceGuild, targetGuild, progressChannel);
86 |
87 | // Show final stats
88 | this.showStats(progressChannel);
89 | this.sendProgress('🎉 Server cloning completed successfully!', progressChannel);
90 |
91 | } catch (error) {
92 | this.sendProgress(`❌ Cloning failed: ${error.message}`, progressChannel);
93 | throw error;
94 | }
95 | }
96 |
97 | async deleteExistingContent(guild, progressChannel) {
98 | this.sendProgress('🗑️ Deleting existing content...', progressChannel);
99 |
100 |
101 | const channels = guild.channels.cache.filter(ch => ch.deletable);
102 | for (const [, channel] of channels) {
103 | try {
104 | await channel.delete();
105 | this.sendProgress(`Deleted channel: ${channel.name}`, progressChannel);
106 | await delay(100);
107 | } catch (error) {
108 | this.sendProgress(`Failed to delete channel ${channel.name}: ${error.message}`, progressChannel);
109 | this.stats.failed++;
110 | }
111 | }
112 |
113 |
114 | const roles = guild.roles.cache.filter(role =>
115 | role.name !== '@everyone' &&
116 | !role.managed &&
117 | role.editable
118 | );
119 |
120 | for (const [, role] of roles) {
121 | try {
122 | await role.delete();
123 | this.sendProgress(`Deleted role: ${role.name}`, progressChannel);
124 | await delay(100);
125 | } catch (error) {
126 | this.sendProgress(`Failed to delete role ${role.name}: ${error.message}`, progressChannel);
127 | this.stats.failed++;
128 | }
129 | }
130 |
131 | this.sendProgress('Cleanup completed.', progressChannel);
132 | }
133 |
134 | async cloneRoles(sourceGuild, targetGuild, progressChannel) {
135 | this.sendProgress('👑 Cloning roles...', progressChannel);
136 |
137 | const roles = sourceGuild.roles.cache
138 | .filter(role => role.name !== '@everyone')
139 | .sort((a, b) => a.position - b.position);
140 |
141 | for (const [, role] of roles) {
142 | try {
143 | const newRole = await targetGuild.roles.create({
144 | name: role.name,
145 | color: role.hexColor,
146 | permissions: role.permissions,
147 | hoist: role.hoist,
148 | mentionable: role.mentionable,
149 | reason: 'Server cloning'
150 | });
151 |
152 | this.roleMapping.set(role.id, newRole.id);
153 | this.sendProgress(`Created role: ${role.name}`, progressChannel);
154 | this.stats.rolesCreated++;
155 | await delay(200);
156 |
157 | } catch (error) {
158 | this.sendProgress(`Failed to create role ${role.name}: ${error.message}`, progressChannel);
159 | this.stats.failed++;
160 | }
161 | }
162 |
163 |
164 | await this.fixRolePositions(sourceGuild, targetGuild, progressChannel);
165 | this.sendProgress('Roles cloning completed.', progressChannel);
166 | }
167 |
168 | async fixRolePositions(sourceGuild, targetGuild, progressChannel) {
169 | try {
170 | const sourceRoles = sourceGuild.roles.cache
171 | .filter(role => role.name !== '@everyone')
172 | .sort((a, b) => b.position - a.position);
173 |
174 | for (const [, sourceRole] of sourceRoles) {
175 | const targetRole = targetGuild.roles.cache.find(r => r.name === sourceRole.name);
176 | if (targetRole && targetRole.editable) {
177 | try {
178 | await targetRole.setPosition(sourceRole.position);
179 | await delay(100);
180 | } catch (error) {
181 |
182 | }
183 | }
184 | }
185 | } catch (error) {
186 | this.sendProgress('Could not fix all role positions', progressChannel);
187 | }
188 | }
189 |
190 | async cloneCategories(sourceGuild, targetGuild, progressChannel) {
191 | this.sendProgress('📁 Cloning categories...', progressChannel);
192 |
193 | const categories = sourceGuild.channels.cache
194 | .filter(ch => ch.type === 'GUILD_CATEGORY')
195 | .sort((a, b) => a.position - b.position);
196 |
197 | for (const [, category] of categories) {
198 | try {
199 | const overwrites = this.mapPermissionOverwrites(category.permissionOverwrites, targetGuild);
200 |
201 | const newCategory = await targetGuild.channels.create(category.name, {
202 | type: 'GUILD_CATEGORY',
203 | permissionOverwrites: overwrites || [],
204 | position: category.position,
205 | reason: 'Server cloning'
206 | });
207 |
208 | this.sendProgress(`Created category: ${category.name}`, progressChannel);
209 | this.stats.categoriesCreated++;
210 | await delay(200);
211 |
212 | } catch (error) {
213 | this.sendProgress(`Failed to create category ${category.name}: ${error.message}`, progressChannel);
214 | this.stats.failed++;
215 | }
216 | }
217 |
218 | this.sendProgress('Categories cloning completed.', progressChannel);
219 | }
220 |
221 | async cloneChannels(sourceGuild, targetGuild, progressChannel) {
222 | this.sendProgress('💬 Cloning channels...', progressChannel);
223 |
224 | const channels = sourceGuild.channels.cache
225 | .filter(ch => ch.type === 'GUILD_TEXT' || ch.type === 'GUILD_VOICE')
226 | .sort((a, b) => a.position - b.position);
227 |
228 | for (const [, channel] of channels) {
229 | try {
230 | const overwrites = this.mapPermissionOverwrites(channel.permissionOverwrites, targetGuild);
231 | const parent = channel.parent ?
232 | targetGuild.channels.cache.find(c => c.name === channel.parent.name && c.type === 'GUILD_CATEGORY') :
233 | null;
234 |
235 | const channelOptions = {
236 | type: channel.type,
237 | parent: parent?.id,
238 | permissionOverwrites: overwrites || [],
239 | position: channel.position,
240 | reason: 'Server cloning'
241 | };
242 |
243 |
244 | if (channel.type === 'GUILD_TEXT') {
245 | channelOptions.topic = channel.topic || '';
246 | channelOptions.nsfw = channel.nsfw;
247 | channelOptions.rateLimitPerUser = channel.rateLimitPerUser;
248 | } else if (channel.type === 'GUILD_VOICE') {
249 | channelOptions.bitrate = channel.bitrate;
250 | channelOptions.userLimit = channel.userLimit;
251 | }
252 |
253 | const newChannel = await targetGuild.channels.create(channel.name, channelOptions);
254 |
255 | const channelType = channel.type === 'GUILD_TEXT' ? 'text' : 'voice';
256 | this.sendProgress(`Created ${channelType} channel: ${channel.name}`, progressChannel);
257 | this.stats.channelsCreated++;
258 | await delay(200);
259 |
260 | } catch (error) {
261 | this.sendProgress(`Failed to create channel ${channel.name}: ${error.message}`, progressChannel);
262 | this.stats.failed++;
263 | }
264 | }
265 |
266 | this.sendProgress('Channels cloning completed.', progressChannel);
267 | }
268 |
269 | async cloneEmojis(sourceGuild, targetGuild, progressChannel) {
270 | this.sendProgress('😀 Cloning emojis...', progressChannel);
271 |
272 | const emojis = sourceGuild.emojis.cache;
273 |
274 | for (const [, emoji] of emojis) {
275 | try {
276 | const emojiURL = emoji.url;
277 | const imageData = await downloadImage(emojiURL);
278 |
279 | await targetGuild.emojis.create(imageData, emoji.name, {
280 | reason: 'Server cloning'
281 | });
282 |
283 | this.sendProgress(`Created emoji: ${emoji.name}`, progressChannel);
284 | this.stats.emojisCreated++;
285 |
286 | await delay(2000);
287 |
288 | } catch (error) {
289 | this.sendProgress(`Failed to create emoji ${emoji.name}: ${error.message}`, progressChannel);
290 | this.stats.failed++;
291 | }
292 | }
293 |
294 | this.sendProgress('Emojis cloning completed.', progressChannel);
295 | }
296 |
297 | async cloneServerInfo(sourceGuild, targetGuild, progressChannel) {
298 | this.sendProgress('🏠 Cloning server info...', progressChannel);
299 |
300 | try {
301 | let iconData = null;
302 |
303 | if (sourceGuild.iconURL()) {
304 | try {
305 | iconData = await downloadImage(sourceGuild.iconURL({ format: 'png', size: 1024 }));
306 | } catch (error) {
307 | this.sendProgress('Could not download server icon', progressChannel);
308 | }
309 | }
310 |
311 | await targetGuild.setName(sourceGuild.name);
312 | this.sendProgress(`Updated server name: ${sourceGuild.name}`, progressChannel);
313 |
314 | if (iconData) {
315 | await targetGuild.setIcon(iconData);
316 | this.sendProgress('Updated server icon', progressChannel);
317 | }
318 |
319 | } catch (error) {
320 | this.sendProgress(`Failed to update server info: ${error.message}`, progressChannel);
321 | this.stats.failed++;
322 | }
323 |
324 | this.sendProgress('Server info cloning completed.', progressChannel);
325 | }
326 |
327 | mapPermissionOverwrites(overwrites, targetGuild) {
328 | const mappedOverwrites = [];
329 |
330 | if (!overwrites || !overwrites.cache) {
331 | return mappedOverwrites;
332 | }
333 |
334 | overwrites.cache.forEach((overwrite) => {
335 | try {
336 | let targetId = overwrite.id;
337 |
338 |
339 | if (overwrite.type === 'role') {
340 | const newRoleId = this.roleMapping.get(overwrite.id);
341 | if (newRoleId) {
342 | targetId = newRoleId;
343 | } else {
344 |
345 | const targetRole = targetGuild.roles.cache.find(r => {
346 | const sourceGuild = overwrites.constructor.name === 'PermissionOverwriteManager' ? overwrites.channel.guild : null;
347 | if (sourceGuild) {
348 | const sourceRole = sourceGuild.roles.cache.get(overwrite.id);
349 | return sourceRole && r.name === sourceRole.name;
350 | }
351 | return false;
352 | });
353 | if (targetRole) {
354 | targetId = targetRole.id;
355 | } else {
356 | return;
357 | }
358 | }
359 | }
360 |
361 | if (overwrite.allow !== undefined && overwrite.deny !== undefined) {
362 | mappedOverwrites.push({
363 | id: targetId,
364 | type: overwrite.type,
365 | allow: overwrite.allow,
366 | deny: overwrite.deny
367 | });
368 | }
369 | } catch (error) {
370 | this.sendProgress(`Skipped permission overwrite due to error: ${error.message}`);
371 | }
372 | });
373 |
374 | return mappedOverwrites;
375 | }
376 |
377 | showStats(progressChannel) {
378 | const total = this.stats.rolesCreated + this.stats.categoriesCreated +
379 | this.stats.channelsCreated + this.stats.emojisCreated;
380 | const successRate = Math.round((total/(total + this.stats.failed)) * 100) || 0;
381 |
382 | const statsMessage = `
383 | 📊 **Cloning Statistics:**
384 | ✅ Roles Created: ${this.stats.rolesCreated}
385 | ✅ Categories Created: ${this.stats.categoriesCreated}
386 | ✅ Channels Created: ${this.stats.channelsCreated}
387 | ✅ Emojis Created: ${this.stats.emojisCreated}
388 | ❌ Failed Operations: ${this.stats.failed}
389 | 📈 Success Rate: ${successRate}%`;
390 |
391 | this.sendProgress(statsMessage, progressChannel);
392 | }
393 |
394 | sendProgress(message, progressChannel) {
395 | if (progressChannel) {
396 | if (message.length > 2000) {
397 | const chunks = message.match(/.{1,2000}/g);
398 | chunks.forEach(chunk => {
399 | progressChannel.send(chunk).then(sentMsg => {
400 | botMessageIds.add(sentMsg.id);
401 | if (botMessageIds.size > 50) {
402 | const firstId = botMessageIds.values().next().value;
403 | botMessageIds.delete(firstId);
404 | }
405 | }).catch(() => {});
406 | });
407 | } else {
408 | progressChannel.send(message).then(sentMsg => {
409 | botMessageIds.add(sentMsg.id);
410 | if (botMessageIds.size > 50) {
411 | const firstId = botMessageIds.values().next().value;
412 | botMessageIds.delete(firstId);
413 | }
414 | }).catch(() => {});
415 | }
416 | }
417 |
418 | if (message.includes('❌') || message.includes('[-]')) {
419 | log.error(message.replace(/❌|✅|📊|📈|🗑️|👑|📁|💬|😀|🏠|🎉/g, '').trim());
420 | } else if (message.includes('✅') || message.includes('[+]')) {
421 | log.success(message.replace(/❌|✅|📊|📈|🗑️|👑|📁|💬|😀|🏠|🎉/g, '').trim());
422 | } else if (message.includes('📊') || message.includes('📈') || message.includes('[i]')) {
423 | log.info(message.replace(/❌|✅|📊|📈|🗑️|👑|📁|💬|😀|🏠|🎉/g, '').trim());
424 | } else {
425 | console.log(message);
426 | }
427 | }
428 | }
429 |
430 | const pendingOperations = new Map();
431 |
432 | const client = new Client();
433 |
434 | const botMessageIds = new Set();
435 |
436 | client.on('messageCreate', async (message) => {
437 | if (message.author.id === client.user.id && botMessageIds.has(message.id)) {
438 | return;
439 | }
440 |
441 | if (message.author.bot && message.author.id !== client.user.id) return;
442 |
443 | const isDM = message.channel.type === 'DM';
444 |
445 | const allowedUserIds = process.env.ALLOWED_USER_IDS?.split(',').map(id => id.trim()) || [];
446 | const isAllowedUser = allowedUserIds.includes(message.author.id);
447 |
448 | if (pendingOperations.has(message.author.id)) {
449 | const operation = pendingOperations.get(message.author.id);
450 |
451 | if (!isAllowedUser) {
452 | return;
453 | }
454 |
455 | const messageContent = message.content.toLowerCase().trim();
456 |
457 | if (message.content.length > 10) {
458 | return;
459 | }
460 |
461 | const validResponses = ['y', 'n', 'yes', 'no'];
462 | if (!validResponses.includes(messageContent)) {
463 | if (message.content.length <= 5) {
464 | message.channel.send('❌ Please respond with "y" or "n"').then(sentMsg => {
465 | botMessageIds.add(sentMsg.id);
466 | }).catch(() => {});
467 | }
468 | return;
469 | }
470 |
471 | if (operation.step === 'confirmProceed') {
472 | if (messageContent === 'y' || messageContent === 'yes') {
473 | message.channel.send('❓ Do you want to clone emojis too? (y/n)').then(sentMsg => {
474 | botMessageIds.add(sentMsg.id);
475 | }).catch(() => {});
476 | operation.step = 'confirmEmojis';
477 | return;
478 | } else if (messageContent === 'n' || messageContent === 'no') {
479 | message.channel.send('❌ Operation cancelled.').then(sentMsg => {
480 | botMessageIds.add(sentMsg.id);
481 | }).catch(() => {});
482 | pendingOperations.delete(message.author.id);
483 | return;
484 | }
485 | } else if (operation.step === 'confirmEmojis') {
486 | if (messageContent === 'y' || messageContent === 'yes') {
487 | operation.cloneEmojis = true;
488 | pendingOperations.delete(message.author.id);
489 | message.channel.send('🚀 Starting server cloning process...').then(sentMsg => {
490 | botMessageIds.add(sentMsg.id);
491 | }).catch(() => {});
492 | try {
493 | const cloner = new ServerCloner(client);
494 | await cloner.cloneServer(operation.sourceGuildId, operation.targetGuildId, operation.cloneEmojis, message.channel);
495 | } catch (error) {
496 | message.channel.send(`❌ Error during cloning: ${error.message}`).then(sentMsg => {
497 | botMessageIds.add(sentMsg.id);
498 | }).catch(() => {});
499 | }
500 | return;
501 | } else if (messageContent === 'n' || messageContent === 'no') {
502 | operation.cloneEmojis = false;
503 | pendingOperations.delete(message.author.id);
504 | message.channel.send('🚀 Starting server cloning process (without emojis)...').then(sentMsg => {
505 | botMessageIds.add(sentMsg.id);
506 | }).catch(() => {});
507 | try {
508 | const cloner = new ServerCloner(client);
509 | await cloner.cloneServer(operation.sourceGuildId, operation.targetGuildId, operation.cloneEmojis, message.channel);
510 | } catch (error) {
511 | message.channel.send(`❌ Error during cloning: ${error.message}`).then(sentMsg => {
512 | botMessageIds.add(sentMsg.id);
513 | }).catch(() => {});
514 | }
515 | return;
516 | }
517 | }
518 | }
519 |
520 | if (message.content.startsWith('!clone')) {
521 | if (!isAllowedUser) {
522 | return;
523 | }
524 |
525 | const args = message.content.slice(6).trim().split(/ +/);
526 | const sourceGuildId = args[0];
527 | const targetGuildId = args[1];
528 |
529 | if (!sourceGuildId || !targetGuildId) {
530 | message.channel.send('❌ Usage: `!clone `').then(sentMsg => {
531 | botMessageIds.add(sentMsg.id);
532 | }).catch(() => {});
533 | return;
534 | }
535 |
536 | try {
537 |
538 | const sourceGuild = client.guilds.cache.get(sourceGuildId);
539 | const targetGuild = client.guilds.cache.get(targetGuildId);
540 |
541 | if (!sourceGuild) {
542 | message.channel.send('Source server not found! Make sure you\'re a member.').then(sentMsg => {
543 | botMessageIds.add(sentMsg.id);
544 | }).catch(() => {});
545 | return;
546 | }
547 |
548 | if (!targetGuild) {
549 | message.channel.send('Target server not found! Make sure you\'re a member with admin permissions.').then(sentMsg => {
550 | botMessageIds.add(sentMsg.id);
551 | }).catch(() => {});
552 | return;
553 | }
554 |
555 | pendingOperations.set(message.author.id, {
556 | step: 'confirmProceed',
557 | sourceGuildId,
558 | targetGuildId,
559 | sourceGuildName: sourceGuild.name,
560 | targetGuildName: targetGuild.name,
561 | cloneEmojis: true
562 | });
563 |
564 | message.channel.send(`📋 **Server Cloning Confirmation**
565 | Source Server: **${sourceGuild.name}**
566 | Target Server: **${targetGuild.name}**
567 |
568 | Do you want to proceed? (y/n)`).then(sentMsg => {
569 | botMessageIds.add(sentMsg.id);
570 | }).catch(() => {});
571 | } catch (error) {
572 | message.channel.send(`❌ Error: ${error.message}`).then(sentMsg => {
573 | botMessageIds.add(sentMsg.id);
574 | }).catch(() => {});
575 | }
576 | }
577 | });
578 |
579 | process.on('SIGINT', () => {
580 | log.warning('\nProcess interrupted by user');
581 | process.exit(0);
582 | });
583 |
584 | process.on('unhandledRejection', (error) => {
585 | log.error(`Unhandled rejection: ${error.message}`);
586 | });
587 |
588 | process.on('uncaughtException', (error) => {
589 | log.error(`Uncaught exception: ${error.message}`);
590 | });
591 |
592 | client.login(process.env.TOKEN).then(() => {
593 | log.success('Logged in successfully!');
594 | }).catch((error) => {
595 | log.error(`Login failed: ${error.message}`);
596 | process.exit(1);
597 | });
598 |
599 | module.exports = { ServerCloner };
--------------------------------------------------------------------------------