Adds Seekbar

This commit is contained in:
2025-07-01 01:33:12 +05:30
parent b304a682e8
commit c908577d36
3 changed files with 269 additions and 0 deletions

190
player.js
View File

@@ -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.');
}