<!-- head --><!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>FilaMan - Filament Management Tool</title> <link rel="icon" type="image/png" href="/favicon.ico"> <link rel="stylesheet" href="style.css"> <script> fetch('/api/version') .then(response => response.json()) .then(data => { const versionSpan = document.querySelector('.version'); if (versionSpan) { versionSpan.textContent = 'v' + data.version; } }) .catch(error => console.error('Error fetching version:', error)); </script> </head> <body> <div class="navbar"> <div style="display: flex; align-items: center; gap: 2rem;"> <img src="/logo.png" alt="FilaMan Logo" class="logo"> <div class="logo-text"> <h1>FilaMan<span class="version"></span></h1> <h4>Hollo Lollo Trollo</h4> </div> </div> <nav style="display: flex; gap: 1rem;"> <a href="/">Start</a> <a href="/waage">Scale</a> <a href="/spoolman">Spoolman/Bambu</a> <a href="/about">About</a> <a href="/upgrade">Upgrade</a> </nav> <div class="status-container"> <div class="status-item"> <span class="status-dot" id="bambuDot"></span>B </div> <div class="status-item"> <span class="status-dot" id="spoolmanDot"></span>S </div> <div class="ram-status" id="ramStatus"></div> </div> </div> </body> </html> <!-- head --> <div class="content"> <h1>Firmware Upgrade</h1> <div class="warning"> <strong>Warning:</strong> Do not power off the device during update. </div> <div class="update-options"> <div class="update-section"> <h2>Firmware Update</h2> <p>Upload a new firmware file (filaman_*.bin)</p> <div class="update-form"> <form id="firmwareForm" enctype='multipart/form-data' data-type="firmware"> <input type='file' name='update' accept='.bin' required> <input type='submit' value='Start Firmware Update'> </form> </div> </div> <div class="update-section"> <h2>Webpage Update</h2> <p>Upload a new webpage file (webpage_*.bin)</p> <div class="update-form"> <form id="webpageForm" enctype='multipart/form-data' data-type="webpage"> <input type='file' name='update' accept='.bin' required> <input type='submit' value='Start Webpage Update'> </form> </div> </div> </div> <div class="progress-container" style="display: none;"> <div class="progress-bar">0%</div> </div> <div class="status"></div> </div> <style> .update-options { display: flex; gap: 2rem; margin: 2rem 0; } .update-section { flex: 1; background: #f5f5f5; padding: 1.5rem; border-radius: 8px; } .update-section h2 { margin-top: 0; color: #333; } .update-section p { color: #666; margin-bottom: 1rem; } .progress-container { margin: 20px 0; background: #f0f0f0; border-radius: 4px; overflow: hidden; } .progress-bar { width: 0; height: 20px; background: #4CAF50; transition: width 0.3s ease-in-out; text-align: center; line-height: 20px; color: white; } .status { margin-top: 20px; padding: 10px; border-radius: 4px; display: none; } .status.success { background: #e8f5e9; color: #2e7d32; } .status.error { background: #ffebee; color: #c62828; } .warning { background: #fff3e0; color: #e65100; padding: 15px; border-radius: 4px; margin-bottom: 20px; } </style> <script> // Hide status indicators during update const statusContainer = document.querySelector('.status-container'); if (statusContainer) { statusContainer.style.display = 'none'; } const progress = document.querySelector('.progress-bar'); const progressContainer = document.querySelector('.progress-container'); const status = document.querySelector('.status'); function handleUpdate(e) { e.preventDefault(); const form = e.target; const file = form.update.files[0]; const updateType = form.dataset.type; if (!file) { alert('Please select a file.'); return; } // Validate file name pattern if (updateType === 'firmware' && !file.name.startsWith('upgrade_filaman_firmware_')) { alert('Please select a valid firmware file (upgrade_filaman_firmware_*.bin)'); return; } if (updateType === 'webpage' && !file.name.startsWith('upgrade_filaman_website_')) { alert('Please select a valid webpage file (upgrade_filaman_website_*.bin)'); return; } progressContainer.style.display = 'block'; status.style.display = 'none'; status.className = 'status'; // Reset progress bar progress.style.width = '0%'; progress.textContent = '0%'; // Disable both forms during update document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = true); const xhr = new XMLHttpRequest(); xhr.open('POST', '/update', true); xhr.onload = function() { try { let response = this.responseText; try { const jsonResponse = JSON.parse(response); // Zeige finale Nachricht status.textContent = jsonResponse.message || "Update complete"; status.classList.add(jsonResponse.success ? 'success' : 'error'); status.style.display = 'block'; if (jsonResponse.success) { progress.style.width = '100%'; progress.textContent = '100%'; // Automatischer Neustart nach erfolgreicher Aktualisierung status.textContent = "Update successful! Restarting device..."; setTimeout(() => { window.location.reload(); }, 5000); } else { document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); } } catch (e) { console.error('JSON parse error:', e); status.textContent = 'Update failed: Invalid response from server'; status.classList.add('error'); document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); } } catch (error) { status.textContent = 'Error: ' + error.message; status.classList.add('error'); status.style.display = 'block'; document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); } }; xhr.onerror = function() { status.textContent = 'Update failed: Network error'; status.classList.add('error'); status.style.display = 'block'; document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); }; const formData = new FormData(); formData.append('update', file); xhr.send(formData); } document.getElementById('firmwareForm').addEventListener('submit', handleUpdate); document.getElementById('webpageForm').addEventListener('submit', handleUpdate); </script> </body> </html>