aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIndrajith K L2025-07-01 01:33:12 +0530
committerIndrajith K L2025-07-01 01:33:12 +0530
commitc908577d3621aab29a40025fb69fd8695e021e57 (patch)
tree60def56fdccf59863b7de9f5b7d7eb9fa734d567
parentb304a682e8545d8b2458c23963ebe7addd924321 (diff)
downloadretrowave-player-c908577d3621aab29a40025fb69fd8695e021e57.tar.gz
retrowave-player-c908577d3621aab29a40025fb69fd8695e021e57.tar.bz2
retrowave-player-c908577d3621aab29a40025fb69fd8695e021e57.zip
Adds Seekbar
-rw-r--r--hg.css69
-rw-r--r--index.html10
-rw-r--r--player.js190
3 files changed, 269 insertions, 0 deletions
diff --git a/hg.css b/hg.css
index a2c2bd3..5451dec 100644
--- a/hg.css
+++ b/hg.css
@@ -427,6 +427,75 @@ canvas {
top: 0;
}
+.progress-bar-container {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 55px;
+ background: linear-gradient(145deg, rgba(0, 0, 0, 0.95), rgba(0, 0, 0, 0.85));
+ border-top: 2px solid #ff2975;
+ z-index: 1000;
+ padding: 10px 20px;
+ box-shadow:
+ 0 -2px 10px rgba(0, 0, 0, 0.6),
+ 0 0 15px rgba(255, 41, 117, 0.2);
+}
+
+.progress-info {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 6px;
+ font-family: "VCR", monospace;
+ font-size: 10px;
+ color: #00ffff;
+ text-shadow: 0 0 5px rgba(0, 255, 255, 0.5);
+}
+
+.progress-bar {
+ position: relative;
+ height: 6px;
+ background: linear-gradient(145deg, rgba(0, 0, 0, 0.8), rgba(20, 20, 20, 0.9));
+ border: 1px solid #333;
+ border-radius: 3px;
+ cursor: pointer;
+ overflow: hidden;
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.8);
+}
+
+.progress-fill {
+ height: 100%;
+ background: linear-gradient(90deg, #ff2975, #00ffff);
+ border-radius: 3px;
+ width: 0%;
+ transition: width 0.1s ease-out;
+ box-shadow: 0 0 8px rgba(255, 41, 117, 0.4);
+}
+
+.progress-handle {
+ position: absolute;
+ top: -4px;
+ width: 14px;
+ height: 14px;
+ background: radial-gradient(circle, #00ffff, #ff2975);
+ border: 1px solid #fff;
+ border-radius: 50%;
+ cursor: pointer;
+ opacity: 0;
+ transition: opacity 0.3s ease;
+ box-shadow: 0 0 8px rgba(0, 255, 255, 0.6);
+ transform: translateX(-50%);
+}
+
+.progress-bar:hover .progress-handle {
+ opacity: 1;
+}
+
+.progress-handle:hover {
+ transform: translateX(-50%) scale(1.1);
+ box-shadow: 0 0 12px rgba(0, 255, 255, 0.8);
+}
+
.player-controls {
position: absolute;
top: 0;
diff --git a/index.html b/index.html
index 9892c5f..4d67354 100644
--- a/index.html
+++ b/index.html
@@ -129,6 +129,16 @@
</div>
</div>
</div>
+ <div id="progress-bar-container" class="progress-bar-container">
+ <div class="progress-info">
+ <span id="current-time">00:00</span>
+ <span id="total-time">00:00</span>
+ </div>
+ <div id="progress-bar" class="progress-bar">
+ <div id="progress-fill" class="progress-fill"></div>
+ <div id="progress-handle" class="progress-handle"></div>
+ </div>
+ </div>
<div id="codef-canvas"></div>
<div class="OVR hidden"></div>
<div class="ERRORS hidden"></div>
diff --git a/player.js b/player.js
index 135f1f9..1d147ad 100644
--- a/player.js
+++ b/player.js
@@ -18,6 +18,16 @@
let currentEffectIndex = 0;
const modalEl = document.getElementById("intro-modal");
+ // Progress bar elements (initialized later to avoid null references)
+ let progressBarContainer;
+ let progressBar;
+ let progressFill;
+ let progressHandle;
+ let currentTimeEl;
+ let totalTimeEl;
+ let progressUpdateInterval;
+ let isDragging = false;
+
// const uploadInfoEl = document.getElementById("upload-info");
const fileUploadEl = document.getElementById("file-upload");
let volume = 1;
@@ -111,6 +121,7 @@
});
initHydra();
initControls();
+ initProgressBar();
});
document.getElementById("history").addEventListener("click", () => {
@@ -223,6 +234,18 @@
onend: function () {
playNextTrack();
},
+ onload: function () {
+ updateProgressBar();
+ },
+ onplay: function () {
+ startProgressTracking();
+ },
+ onpause: function () {
+ stopProgressTracking();
+ },
+ onstop: function () {
+ stopProgressTracking();
+ },
});
setVolume();
isPlaying = true;
@@ -318,6 +341,7 @@ https://retrowave.ru/${musicData.streamUrl}
}
function resetHowler(destroy = false) {
+ stopProgressTracking();
howlerInstance.stop();
if (destroy) {
howlerInstance.unload();
@@ -325,6 +349,134 @@ https://retrowave.ru/${musicData.streamUrl}
}
}
+ // Progress Bar Utility Functions
+ function formatTime(seconds) {
+ const mins = Math.floor(seconds / 60);
+ const secs = Math.floor(seconds % 60);
+ return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
+ }
+
+ function updateProgressBar() {
+ if (!howlerInstance || isDragging || !progressFill || !progressHandle || !currentTimeEl || !totalTimeEl) return;
+
+ const seek = howlerInstance.seek() || 0;
+ const duration = howlerInstance.duration() || 0;
+
+ if (duration > 0) {
+ const percentage = (seek / duration) * 100;
+ progressFill.style.width = `${percentage}%`;
+ progressHandle.style.left = `${percentage}%`;
+
+ currentTimeEl.textContent = formatTime(seek);
+ totalTimeEl.textContent = formatTime(duration);
+ }
+ }
+
+ function startProgressTracking() {
+ if (progressUpdateInterval) {
+ clearInterval(progressUpdateInterval);
+ }
+ progressUpdateInterval = setInterval(updateProgressBar, 100);
+ }
+
+ function stopProgressTracking() {
+ if (progressUpdateInterval) {
+ clearInterval(progressUpdateInterval);
+ progressUpdateInterval = null;
+ }
+ }
+
+ function seekToPosition(percentage) {
+ if (!howlerInstance) return;
+
+ const duration = howlerInstance.duration() || 0;
+ if (duration > 0) {
+ const seekTime = (percentage / 100) * duration;
+ howlerInstance.seek(seekTime);
+ updateProgressBar();
+ }
+ }
+
+ function initProgressBar() {
+ // Initialize DOM elements
+ progressBarContainer = document.getElementById("progress-bar-container");
+ progressBar = document.getElementById("progress-bar");
+ progressFill = document.getElementById("progress-fill");
+ progressHandle = document.getElementById("progress-handle");
+ currentTimeEl = document.getElementById("current-time");
+ totalTimeEl = document.getElementById("total-time");
+
+ if (!progressBar || !progressFill || !progressHandle || !currentTimeEl || !totalTimeEl) {
+ console.warn("Progress bar elements not found");
+ return;
+ }
+
+ // Click to seek
+ progressBar.addEventListener("click", (e) => {
+ if (isDragging) return;
+
+ const rect = progressBar.getBoundingClientRect();
+ const percentage = ((e.clientX - rect.left) / rect.width) * 100;
+ seekToPosition(Math.max(0, Math.min(100, percentage)));
+ });
+
+ // Drag to seek functionality
+ let startX = 0;
+ let startPercentage = 0;
+
+ progressHandle.addEventListener("mousedown", (e) => {
+ isDragging = true;
+ startX = e.clientX;
+ const rect = progressBar.getBoundingClientRect();
+ startPercentage = ((startX - rect.left) / rect.width) * 100;
+
+ document.addEventListener("mousemove", handleMouseMove);
+ document.addEventListener("mouseup", handleMouseUp);
+ e.preventDefault();
+ });
+
+ function handleMouseMove(e) {
+ if (!isDragging) return;
+
+ const rect = progressBar.getBoundingClientRect();
+ const percentage = ((e.clientX - rect.left) / rect.width) * 100;
+ const clampedPercentage = Math.max(0, Math.min(100, percentage));
+
+ progressFill.style.width = `${clampedPercentage}%`;
+ progressHandle.style.left = `${clampedPercentage}%`;
+
+ if (howlerInstance) {
+ const duration = howlerInstance.duration() || 0;
+ if (duration > 0) {
+ const seekTime = (clampedPercentage / 100) * duration;
+ currentTimeEl.textContent = formatTime(seekTime);
+ }
+ }
+ }
+
+ function handleMouseUp(e) {
+ if (!isDragging) return;
+
+ const rect = progressBar.getBoundingClientRect();
+ const percentage = ((e.clientX - rect.left) / rect.width) * 100;
+ const clampedPercentage = Math.max(0, Math.min(100, percentage));
+
+ seekToPosition(clampedPercentage);
+ isDragging = false;
+
+ document.removeEventListener("mousemove", handleMouseMove);
+ document.removeEventListener("mouseup", handleMouseUp);
+ }
+
+ // Touch support for mobile
+ progressBar.addEventListener("touchstart", (e) => {
+ const touch = e.touches[0];
+ const rect = progressBar.getBoundingClientRect();
+ const percentage = ((touch.clientX - rect.left) / rect.width) * 100;
+ seekToPosition(Math.max(0, Math.min(100, percentage)));
+ });
+ }
+
function initControls() {
refreshBtn.addEventListener("click", () => {
playNextTrack();
@@ -1267,6 +1419,7 @@ https://retrowave.ru/${musicData.streamUrl}
addTerminalLine(' pause - Pause playback');
addTerminalLine(' next - Skip to next track');
addTerminalLine(' volume [0-10] - Set volume (0-10)');
+ addTerminalLine(' seek [time] - Seek to time (seconds or mm:ss)');
addTerminalLine(' status - Show current track info');
addTerminalLine(' history - Download playlist history');
addTerminalLine(' effect [list|name]- Change/list visual effects');
@@ -1319,12 +1472,49 @@ https://retrowave.ru/${musicData.streamUrl}
}
break;
+ case 'seek':
+ if (args[1] && howlerInstance) {
+ let seekTime = 0;
+ const input = args[1];
+
+ if (input.includes(':')) {
+ const [mins, secs] = input.split(':').map(Number);
+ seekTime = (mins * 60) + secs;
+ } else {
+ seekTime = parseFloat(input);
+ }
+
+ const duration = howlerInstance.duration() || 0;
+ if (seekTime >= 0 && seekTime <= duration) {
+ howlerInstance.seek(seekTime);
+ updateProgressBar();
+ addTerminalLine(`Seeked to ${formatTime(seekTime)}`);
+ } else {
+ addTerminalLine(`Invalid seek time. Duration: ${formatTime(duration)}`);
+ }
+ } else if (!howlerInstance) {
+ addTerminalLine('No track loaded.');
+ } else {
+ if (howlerInstance) {
+ const seek = howlerInstance.seek() || 0;
+ const duration = howlerInstance.duration() || 0;
+ addTerminalLine(`Current position: ${formatTime(seek)} / ${formatTime(duration)}`);
+ }
+ }
+ break;
+
case 'status':
if (currentTracks.length > 0) {
const track = currentTracks[0];
addTerminalLine(`Now playing: ${track.title}`);
addTerminalLine(`Status: ${isPlaying ? 'Playing' : 'Paused'}`);
addTerminalLine(`Volume: ${Math.round(volume * 10)}/10`);
+ if (howlerInstance) {
+ const seek = howlerInstance.seek() || 0;
+ const duration = howlerInstance.duration() || 0;
+ const progress = duration > 0 ? ((seek / duration) * 100).toFixed(1) : 0;
+ addTerminalLine(`Progress: ${formatTime(seek)} / ${formatTime(duration)} (${progress}%)`);
+ }
} else {
addTerminalLine('No track loaded.');
}