- Joined
- 11 Jun 2026
- Messages
- 18
- Reaction score
- 511
- Points
- 78
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
