Tokipo commited on
Commit
46fdce4
·
verified ·
1 Parent(s): 8bb61b2

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +415 -0
index.html ADDED
@@ -0,0 +1,415 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Mineflayer Bot Manager</title>
7
+ <script src="/socket.io/socket.io.js"></script>
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
17
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
18
+ min-height: 100vh;
19
+ padding: 20px;
20
+ }
21
+
22
+ .container {
23
+ max-width: 1400px;
24
+ margin: 0 auto;
25
+ }
26
+
27
+ .header {
28
+ background: white;
29
+ border-radius: 10px;
30
+ padding: 20px;
31
+ margin-bottom: 20px;
32
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
33
+ }
34
+
35
+ .header h1 {
36
+ color: #333;
37
+ margin-bottom: 10px;
38
+ }
39
+
40
+ .stats {
41
+ display: flex;
42
+ gap: 20px;
43
+ flex-wrap: wrap;
44
+ }
45
+
46
+ .stat-card {
47
+ background: #f8f9fa;
48
+ padding: 10px 20px;
49
+ border-radius: 5px;
50
+ border-left: 4px solid #667eea;
51
+ }
52
+
53
+ .stat-card .label {
54
+ font-size: 12px;
55
+ color: #666;
56
+ text-transform: uppercase;
57
+ }
58
+
59
+ .stat-card .value {
60
+ font-size: 24px;
61
+ font-weight: bold;
62
+ color: #333;
63
+ }
64
+
65
+ .controls {
66
+ background: white;
67
+ border-radius: 10px;
68
+ padding: 15px;
69
+ margin-bottom: 20px;
70
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
71
+ }
72
+
73
+ .btn {
74
+ background: #667eea;
75
+ color: white;
76
+ border: none;
77
+ padding: 10px 20px;
78
+ border-radius: 5px;
79
+ cursor: pointer;
80
+ font-size: 14px;
81
+ transition: background 0.3s;
82
+ }
83
+
84
+ .btn:hover {
85
+ background: #5a67d8;
86
+ }
87
+
88
+ .btn:disabled {
89
+ background: #ccc;
90
+ cursor: not-allowed;
91
+ }
92
+
93
+ .bot-grid {
94
+ display: grid;
95
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
96
+ gap: 15px;
97
+ }
98
+
99
+ .bot-card {
100
+ background: white;
101
+ border-radius: 10px;
102
+ padding: 15px;
103
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
104
+ transition: transform 0.3s;
105
+ }
106
+
107
+ .bot-card:hover {
108
+ transform: translateY(-2px);
109
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
110
+ }
111
+
112
+ .bot-header {
113
+ display: flex;
114
+ justify-content: space-between;
115
+ align-items: center;
116
+ margin-bottom: 10px;
117
+ }
118
+
119
+ .bot-name {
120
+ font-weight: bold;
121
+ font-size: 16px;
122
+ color: #333;
123
+ }
124
+
125
+ .bot-status {
126
+ padding: 4px 8px;
127
+ border-radius: 12px;
128
+ font-size: 12px;
129
+ font-weight: bold;
130
+ }
131
+
132
+ .status-connected {
133
+ background: #d4edda;
134
+ color: #155724;
135
+ }
136
+
137
+ .status-disconnected {
138
+ background: #f8d7da;
139
+ color: #721c24;
140
+ }
141
+
142
+ .status-connecting {
143
+ background: #fff3cd;
144
+ color: #856404;
145
+ }
146
+
147
+ .bot-info {
148
+ display: grid;
149
+ grid-template-columns: repeat(2, 1fr);
150
+ gap: 10px;
151
+ margin-bottom: 10px;
152
+ }
153
+
154
+ .info-item {
155
+ display: flex;
156
+ flex-direction: column;
157
+ }
158
+
159
+ .info-label {
160
+ font-size: 11px;
161
+ color: #666;
162
+ text-transform: uppercase;
163
+ }
164
+
165
+ .info-value {
166
+ font-size: 14px;
167
+ color: #333;
168
+ font-weight: 500;
169
+ }
170
+
171
+ .bot-actions {
172
+ display: flex;
173
+ gap: 10px;
174
+ }
175
+
176
+ .btn-small {
177
+ padding: 6px 12px;
178
+ font-size: 12px;
179
+ }
180
+
181
+ .btn-reconnect {
182
+ background: #28a745;
183
+ }
184
+
185
+ .btn-reconnect:hover {
186
+ background: #218838;
187
+ }
188
+
189
+ .notification {
190
+ position: fixed;
191
+ top: 20px;
192
+ right: 20px;
193
+ padding: 15px 20px;
194
+ border-radius: 5px;
195
+ background: white;
196
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
197
+ display: none;
198
+ animation: slideIn 0.3s;
199
+ }
200
+
201
+ .notification.success {
202
+ border-left: 4px solid #28a745;
203
+ }
204
+
205
+ .notification.error {
206
+ border-left: 4px solid #dc3545;
207
+ }
208
+
209
+ @keyframes slideIn {
210
+ from {
211
+ transform: translateX(100%);
212
+ opacity: 0;
213
+ }
214
+ to {
215
+ transform: translateX(0);
216
+ opacity: 1;
217
+ }
218
+ }
219
+
220
+ .loading {
221
+ text-align: center;
222
+ padding: 40px;
223
+ color: white;
224
+ }
225
+ </style>
226
+ </head>
227
+ <body>
228
+ <div class="container">
229
+ <div class="header">
230
+ <h1>🤖 Mineflayer Bot Manager</h1>
231
+ <div class="stats">
232
+ <div class="stat-card">
233
+ <div class="label">Total Bots</div>
234
+ <div class="value" id="totalBots">0</div>
235
+ </div>
236
+ <div class="stat-card">
237
+ <div class="label">Connected</div>
238
+ <div class="value" id="connectedBots">0</div>
239
+ </div>
240
+ <div class="stat-card">
241
+ <div class="label">Disconnected</div>
242
+ <div class="value" id="disconnectedBots">0</div>
243
+ </div>
244
+ <div class="stat-card">
245
+ <div class="label">Total Deaths</div>
246
+ <div class="value" id="totalDeaths">0</div>
247
+ </div>
248
+ </div>
249
+ </div>
250
+
251
+ <div class="controls">
252
+ <button class="btn" onclick="refreshSheet()">🔄 Refresh from Sheet</button>
253
+ <span style="margin-left: 10px; color: #666; font-size: 14px;">
254
+ Auto-refresh every 30 seconds
255
+ </span>
256
+ </div>
257
+
258
+ <div id="botContainer" class="bot-grid">
259
+ <div class="loading">Loading bots...</div>
260
+ </div>
261
+ </div>
262
+
263
+ <div id="notification" class="notification"></div>
264
+
265
+ <script>
266
+ const socket = io();
267
+ let botsData = [];
268
+
269
+ socket.on('connect', () => {
270
+ console.log('Connected to server');
271
+ showNotification('Connected to server', 'success');
272
+ });
273
+
274
+ socket.on('disconnect', () => {
275
+ console.log('Disconnected from server');
276
+ showNotification('Disconnected from server', 'error');
277
+ });
278
+
279
+ socket.on('botUpdate', (data) => {
280
+ botsData = data;
281
+ updateUI();
282
+ });
283
+
284
+ socket.on('reconnectResult', (result) => {
285
+ if (result.success) {
286
+ showNotification(`Bot ${result.botName} is reconnecting...`, 'success');
287
+ } else {
288
+ showNotification(`Cannot reconnect ${result.botName} yet. Wait 1 hour between reconnects.`, 'error');
289
+ }
290
+ });
291
+
292
+ function updateUI() {
293
+ const container = document.getElementById('botContainer');
294
+
295
+ if (botsData.length === 0) {
296
+ container.innerHTML = '<div class="loading">No bots configured. Add bots to the Google Sheet.</div>';
297
+ updateStats(0, 0, 0, 0);
298
+ return;
299
+ }
300
+
301
+ let html = '';
302
+ let totalBots = 0;
303
+ let connectedBots = 0;
304
+ let disconnectedBots = 0;
305
+ let totalDeaths = 0;
306
+
307
+ botsData.forEach(bot => {
308
+ totalBots++;
309
+ if (bot.status === 'Connected') {
310
+ connectedBots++;
311
+ } else {
312
+ disconnectedBots++;
313
+ }
314
+ totalDeaths += bot.deathCount;
315
+
316
+ const statusClass = bot.status === 'Connected' ? 'status-connected' :
317
+ bot.status === 'Connecting...' ? 'status-connecting' :
318
+ 'status-disconnected';
319
+
320
+ const uptime = formatUptime(bot.uptime);
321
+ const disconnectTime = bot.disconnectTime ?
322
+ formatTimeSince(bot.disconnectTime) : 'N/A';
323
+
324
+ html += `
325
+ <div class="bot-card">
326
+ <div class="bot-header">
327
+ <div class="bot-name">${bot.botName}</div>
328
+ <div class="bot-status ${statusClass}">${bot.status}</div>
329
+ </div>
330
+ <div class="bot-info">
331
+ <div class="info-item">
332
+ <span class="info-label">Uptime</span>
333
+ <span class="info-value">${uptime}</span>
334
+ </div>
335
+ <div class="info-item">
336
+ <span class="info-label">Deaths</span>
337
+ <span class="info-value">${bot.deathCount}</span>
338
+ </div>
339
+ ${bot.status === 'Disconnected' ? `
340
+ <div class="info-item">
341
+ <span class="info-label">Disconnected</span>
342
+ <span class="info-value">${disconnectTime}</span>
343
+ </div>
344
+ ` : ''}
345
+ </div>
346
+ <div class="bot-actions">
347
+ ${bot.canReconnect && bot.status === 'Disconnected' ? `
348
+ <button class="btn btn-small btn-reconnect" onclick="reconnectBot('${bot.botName}')">
349
+ 🔌 Reconnect
350
+ </button>
351
+ ` : ''}
352
+ ${!bot.canReconnect && bot.status === 'Disconnected' ? `
353
+ <button class="btn btn-small" disabled>
354
+ ⏰ Wait to reconnect
355
+ </button>
356
+ ` : ''}
357
+ </div>
358
+ </div>
359
+ `;
360
+ });
361
+
362
+ container.innerHTML = html;
363
+ updateStats(totalBots, connectedBots, disconnectedBots, totalDeaths);
364
+ }
365
+
366
+ function updateStats(total, connected, disconnected, deaths) {
367
+ document.getElementById('totalBots').textContent = total;
368
+ document.getElementById('connectedBots').textContent = connected;
369
+ document.getElementById('disconnectedBots').textContent = disconnected;
370
+ document.getElementById('totalDeaths').textContent = deaths;
371
+ }
372
+
373
+ function formatUptime(seconds) {
374
+ if (seconds === 0) return '0s';
375
+
376
+ const hours = Math.floor(seconds / 3600);
377
+ const minutes = Math.floor((seconds % 3600) / 60);
378
+ const secs = seconds % 60;
379
+
380
+ if (hours > 0) {
381
+ return `${hours}h ${minutes}m`;
382
+ } else if (minutes > 0) {
383
+ return `${minutes}m ${secs}s`;
384
+ } else {
385
+ return `${secs}s`;
386
+ }
387
+ }
388
+
389
+ function formatTimeSince(timestamp) {
390
+ const seconds = Math.floor((Date.now() - timestamp) / 1000);
391
+ return formatUptime(seconds) + ' ago';
392
+ }
393
+
394
+ function reconnectBot(botName) {
395
+ socket.emit('reconnectBot', botName);
396
+ }
397
+
398
+ function refreshSheet() {
399
+ socket.emit('refreshSheet');
400
+ showNotification('Refreshing from Google Sheet...', 'success');
401
+ }
402
+
403
+ function showNotification(message, type) {
404
+ const notification = document.getElementById('notification');
405
+ notification.textContent = message;
406
+ notification.className = `notification ${type}`;
407
+ notification.style.display = 'block';
408
+
409
+ setTimeout(() => {
410
+ notification.style.display = 'none';
411
+ }, 3000);
412
+ }
413
+ </script>
414
+ </body>
415
+ </html>