diff --git a/static/app.js b/static/app.js index 49da1b6..48949c5 100644 --- a/static/app.js +++ b/static/app.js @@ -4,6 +4,11 @@ let currentStatus = null; let currentVolume = 100; let isUpdatingVolume = false; +// Progress Bar Variables +let localElapsed = 0; +let totalDuration = 0; +let isPlaying = false; + // DOM Elements const statusDot = document.getElementById('status-dot'); const statusText = document.getElementById('status-text'); @@ -34,6 +39,12 @@ const emptyQueueMsg = document.getElementById('empty-queue-msg'); const queueCountBadge = document.getElementById('queue-count'); const toastContainer = document.getElementById('toast-container'); +// Progress Bar DOM Elements +const progressContainer = document.getElementById('progress-container'); +const timeElapsed = document.getElementById('time-elapsed'); +const timeTotal = document.getElementById('time-total'); +const progressBarFill = document.getElementById('progress-bar-fill'); + // Initialize document.addEventListener('DOMContentLoaded', () => { // Initial fetch @@ -45,6 +56,17 @@ document.addEventListener('DOMContentLoaded', () => { fetchStatus(); } }, 1000); + + // Start Smooth Progress Tracker (every 100ms) + setInterval(() => { + if (isPlaying && currentStatus && currentStatus.current) { + localElapsed += 0.1; + if (totalDuration > 0 && localElapsed > totalDuration) { + localElapsed = totalDuration; + } + updateProgressBar(); + } + }, 100); // Bind Event Listeners bindEvents(); @@ -139,6 +161,28 @@ async function fetchStatus() { } } +// Progress Bar Helpers +function formatTime(secs) { + if (secs === null || secs === undefined || isNaN(secs) || secs < 0) return "0:00"; + const h = Math.floor(secs / 3600); + const m = Math.floor((secs % 3600) / 60); + const s = Math.floor(secs % 60); + const formattedSecs = s < 10 ? `0${s}` : s; + if (h > 0) { + const formattedMins = m < 10 ? `0${m}` : m; + return `${h}:${formattedMins}:${formattedSecs}`; + } + return `${m}:${formattedSecs}`; +} + +function updateProgressBar() { + timeElapsed.textContent = formatTime(localElapsed); + if (totalDuration > 0) { + const pct = Math.min((localElapsed / totalDuration) * 100, 100); + progressBarFill.style.width = `${pct}%`; + } +} + // Update UI States function updateUI(status) { // 1. Connection Status & Available Channels @@ -219,6 +263,24 @@ function updateUI(status) { trackLink.href = status.current.url || '#'; trackLink.style.display = status.current.url ? 'inline-flex' : 'none'; + // Sync progress bar values + totalDuration = status.current.duration || 0; + localElapsed = status.current.elapsed || 0; + isPlaying = status.playing; // Update playing state + + // Show progress bar + progressContainer.style.display = 'flex'; + timeElapsed.textContent = formatTime(localElapsed); + + if (totalDuration > 0) { + timeTotal.textContent = formatTime(totalDuration); + const pct = Math.min((localElapsed / totalDuration) * 100, 100); + progressBarFill.style.width = `${pct}%`; + } else { + timeTotal.textContent = "Live"; + progressBarFill.style.width = "100%"; + } + // Vinyl animation if (status.playing) { vinylRecord.classList.add('playing'); @@ -233,6 +295,12 @@ function updateUI(status) { trackLink.style.display = 'none'; vinylRecord.classList.remove('playing'); musicWave.classList.remove('active'); + + // Hide progress bar + progressContainer.style.display = 'none'; + isPlaying = false; + localElapsed = 0; + totalDuration = 0; } // 3. Play/Pause Button State diff --git a/static/index.html b/static/index.html index 654ace9..9ee970f 100644 --- a/static/index.html +++ b/static/index.html @@ -90,6 +90,15 @@ + +
+