const elements = { startBtn: document.getElementById('startBtn'), stopBtn: document.getElementById('stopBtn'), clearLogsBtn: document.getElementById('clearLogsBtn'), errorBanner: document.getElementById('errorBanner'), successBanner: document.getElementById('successBanner'), connectionStatus: document.getElementById('connectionStatus'), currentState: document.getElementById('currentState'), totalItems: document.getElementById('totalItems'), currentPage: document.getElementById('currentPage'), lastRunTime: document.getElementById('lastRunTime'), progressBar: document.getElementById('progressBar'), progressLabel: document.getElementById('progressLabel'), csvLabel: document.getElementById('csvLabel'), logOutput: document.getElementById('logOutput'), }; let logCursor = 0; let pollTimer = null; let running = false; let screenshotTimer = null; function setBanner(element, message) { if (!message) { element.classList.add('hidden'); element.textContent = ''; return; } element.textContent = message; element.classList.remove('hidden'); } function showError(message) { setBanner(elements.errorBanner, message); setBanner(elements.successBanner, ''); } function showSuccess(message) { setBanner(elements.successBanner, message); setBanner(elements.errorBanner, ''); } function clearBanners() { setBanner(elements.errorBanner, ''); setBanner(elements.successBanner, ''); } function setRunningState(isRunning) { running = isRunning; elements.startBtn.disabled = isRunning; elements.stopBtn.disabled = !isRunning; elements.connectionStatus.textContent = isRunning ? 'Running' : 'Ready'; if (isRunning) { elements.connectionStatus.parentElement.querySelector('.dot').style.background = '#f59e0b'; } else { elements.connectionStatus.parentElement.querySelector('.dot').style.background = '#22c55e'; } } function updateStatusPanel(data) { elements.currentState.textContent = data.current_state || 'Idle'; elements.totalItems.textContent = String(data.total_items_found ?? 0); elements.currentPage.textContent = String(data.current_page ?? 0); elements.lastRunTime.textContent = data.last_run_time || '-'; const progress = Number(data.progress || 0); elements.progressBar.style.width = `${Math.max(0, Math.min(100, progress))}%`; elements.progressLabel.textContent = `${Math.max(0, Math.min(100, progress))}%`; if (data.last_error) { showError(data.last_error); } } function appendLogs(logs) { if (!Array.isArray(logs) || logs.length <= logCursor) { return; } const newLogs = logs.slice(logCursor); if (!newLogs.length) { return; } const current = elements.logOutput.textContent === 'Waiting for the next run...' ? '' : elements.logOutput.textContent; const merged = [current.trimEnd(), ...newLogs].filter(Boolean).join('\n'); elements.logOutput.textContent = merged; elements.logOutput.scrollTop = elements.logOutput.scrollHeight; logCursor = logs.length; } async function fetchStatus() { try { const response = await fetch('/status', { cache: 'no-store' }); const data = await response.json(); setRunningState(Boolean(data.running)); updateStatusPanel(data); appendLogs(data.logs || []); if (!data.running && pollTimer) { window.clearInterval(pollTimer); pollTimer = null; } } catch (error) { console.error(error); } } async function startBot() { clearBanners(); try { const response = await fetch('/start', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}), }); const data = await response.json(); if (!response.ok || !data.ok) { showError(data.error || 'Failed to start automation.'); return; } showSuccess('Automation started.'); logCursor = 0; elements.logOutput.textContent = 'Waiting for the next run...'; setRunningState(true); if (!pollTimer) { pollTimer = window.setInterval(fetchStatus, 2000); } await fetchStatus(); } catch (error) { showError(error.message || 'Unable to start the bot.'); } } async function stopBot() { try { const response = await fetch('/stop', { method: 'POST' }); const data = await response.json(); showSuccess(data.message || 'Stop requested.'); await fetchStatus(); } catch (error) { showError(error.message || 'Unable to stop the bot.'); } } function clearLogs() { logCursor = 0; elements.logOutput.textContent = 'Waiting for the next run...'; } function boot() { elements.startBtn.addEventListener('click', startBot); elements.stopBtn.addEventListener('click', stopBot); elements.clearLogsBtn.addEventListener('click', clearLogs); setRunningState(false); fetchStatus(); pollTimer = window.setInterval(fetchStatus, 2000); const img = document.getElementById('screenshotImg'); if (img) { const refresh = () => { img.src = '/screenshot?ts=' + Date.now(); }; screenshotTimer = window.setInterval(refresh, 3000); refresh(); } } document.addEventListener('DOMContentLoaded', boot);