Spaces:
Running
Running
| const express = require('express') | |
| const http = require('http') | |
| const { Server } = require('socket.io') | |
| const { v4: uuidv4 } = require('uuid') | |
| const { createBotInstance } = require('./index') | |
| const app = express() | |
| const server = http.createServer(app) | |
| const io = new Server(server) | |
| app.use(express.json()) | |
| const bots = {} | |
| // ================= BOT START ================= | |
| function startBot(id, cfg) { | |
| bots[id] = bots[id] || { logs: [], instance: null, stopped: false, config: cfg } | |
| const b = bots[id] | |
| const log = (msg) => { | |
| const line = `[${new Date().toLocaleTimeString()}] ${msg}` | |
| b.logs.push(line) | |
| if (b.logs.length > 200) b.logs.shift() | |
| io.emit('log', { id, msg: line }) | |
| } | |
| log(`[SYSTEM] start ${cfg.name}`) | |
| if (b.instance) { | |
| try { b.instance.quit() } catch {} | |
| } | |
| b.instance = createBotInstance(cfg, log, () => { | |
| if (!b.stopped) { | |
| log(`[SYSTEM] reconnecting...`) | |
| setTimeout(() => startBot(id, cfg), 10000) | |
| } | |
| }) | |
| } | |
| // ================= API ================= | |
| app.post('/api/create', (req, res) => { | |
| const id = uuidv4().slice(0, 6) | |
| const cfg = { | |
| name: req.body.name || `AFK_${id}`, | |
| host: req.body.ip, | |
| port: parseInt(req.body.port || 25565), | |
| version: req.body.version || false, | |
| password: req.body.password || "11111111" | |
| } | |
| startBot(id, cfg) | |
| res.json({ id }) | |
| }) | |
| app.get('/api/list', (req, res) => { | |
| const out = {} | |
| for (const id in bots) { | |
| out[id] = { | |
| name: bots[id].config.name, | |
| running: !!bots[id].instance | |
| } | |
| } | |
| res.json(out) | |
| }) | |
| app.post('/api/stop/:id', (req, res) => { | |
| const b = bots[req.params.id] | |
| if (!b) return res.json({ ok: false }) | |
| b.stopped = true | |
| try { b.instance?.quit() } catch {} | |
| b.instance = null | |
| res.json({ ok: true }) | |
| }) | |
| app.post('/api/restart/:id', (req, res) => { | |
| const b = bots[req.params.id] | |
| if (!b) return res.json({ ok: false }) | |
| b.stopped = false | |
| startBot(req.params.id, b.config) | |
| res.json({ ok: true }) | |
| }) | |
| app.get('/api/logs/:id', (req, res) => { | |
| res.json(bots[req.params.id]?.logs || []) | |
| }) | |
| // ================= UI ================= | |
| app.get('/', (req, res) => { | |
| res.send(` | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>AFK KEEPER PRO MAX</title> | |
| <style> | |
| body{ | |
| margin:0; | |
| font-family:Arial; | |
| background:linear-gradient(135deg,#0a0a0a,#111); | |
| color:#0f0; | |
| } | |
| .header{ | |
| padding:20px; | |
| text-align:center; | |
| font-size:24px; | |
| font-weight:bold; | |
| border-bottom:1px solid #0f0; | |
| text-shadow:0 0 10px #0f0; | |
| } | |
| .container{ | |
| display:flex; | |
| gap:20px; | |
| padding:20px; | |
| } | |
| .panel{ | |
| width:300px; | |
| background:#0c0c0c; | |
| border:1px solid #0f0; | |
| padding:15px; | |
| border-radius:10px; | |
| box-shadow:0 0 20px rgba(0,255,0,0.2); | |
| } | |
| input,select{ | |
| width:100%; | |
| padding:10px; | |
| margin:5px 0; | |
| background:#111; | |
| color:#0f0; | |
| border:1px solid #0f0; | |
| border-radius:5px; | |
| outline:none; | |
| } | |
| button{ | |
| width:100%; | |
| padding:10px; | |
| margin-top:10px; | |
| background:#0f0; | |
| color:#000; | |
| font-weight:bold; | |
| border:none; | |
| cursor:pointer; | |
| border-radius:5px; | |
| } | |
| button:hover{ | |
| background:#00ff88; | |
| } | |
| .list{ | |
| flex:1; | |
| background:#0c0c0c; | |
| border:1px solid #0f0; | |
| padding:15px; | |
| border-radius:10px; | |
| } | |
| .card{ | |
| border:1px solid #333; | |
| padding:10px; | |
| margin:10px 0; | |
| border-radius:8px; | |
| } | |
| pre{ | |
| height:250px; | |
| overflow:auto; | |
| background:#000; | |
| padding:10px; | |
| border:1px solid #0f0; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header">⚡ AFK KEEPER PRO MAX ⚡</div> | |
| <div class="container"> | |
| <div class="panel"> | |
| <input id="name" placeholder="Bot Name"> | |
| <input id="ip" placeholder="Server IP"> | |
| <input id="port" placeholder="Port"> | |
| <input id="pass" placeholder="Auth Password"> | |
| <button onclick="create()">CREATE BOT</button> | |
| </div> | |
| <div class="list"> | |
| <div id="bots"></div> | |
| <h3>LOG</h3> | |
| <pre id="log"></pre> | |
| </div> | |
| </div> | |
| <script src="/socket.io/socket.io.js"></script> | |
| <script> | |
| const socket = io() | |
| let current=null | |
| function create(){ | |
| fetch('/api/create',{ | |
| method:'POST', | |
| headers:{'Content-Type':'application/json'}, | |
| body:JSON.stringify({ | |
| name:name.value, | |
| ip:ip.value, | |
| port:port.value, | |
| password:pass.value | |
| }) | |
| }).then(()=>location.reload()) | |
| } | |
| function load(){ | |
| fetch('/api/list') | |
| .then(r=>r.json()) | |
| .then(d=>{ | |
| let html="" | |
| for(let id in d){ | |
| html+=\` | |
| <div class="card"> | |
| <b>\${d[id].name}</b><br> | |
| <button onclick="openLog('\${id}')">VIEW LOG</button> | |
| <button onclick="stop('\${id}')">STOP</button> | |
| <button onclick="restart('\${id}')">RESTART</button> | |
| </div>\` | |
| } | |
| bots.innerHTML=html | |
| }) | |
| } | |
| function openLog(id){ | |
| current=id | |
| fetch('/api/logs/'+id) | |
| .then(r=>r.json()) | |
| .then(d=>{ | |
| log.innerHTML=d.join("\\n") | |
| }) | |
| } | |
| function stop(id){ | |
| fetch('/api/stop/'+id,{method:'POST'}) | |
| } | |
| function restart(id){ | |
| fetch('/api/restart/'+id,{method:'POST'}) | |
| } | |
| socket.on('log',d=>{ | |
| if(d.id===current){ | |
| log.innerHTML+=d.msg+"\\n" | |
| } | |
| }) | |
| load() | |
| </script> | |
| </body> | |
| </html> | |
| `) | |
| }) | |
| server.listen(7860, () => { | |
| console.log("AFK KEEPER PRO MAX RUNNING") | |
| }) |