├── .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 | Typing SVG 3 |

4 | 5 |

6 | 7 | 8 | Join Discord 9 | 10 |

11 | 12 |

13 | Server Cloning 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 }; --------------------------------------------------------------------------------