const playerButton = document.querySelector('.player-button'),
audio = document.querySelector('audio'),
timeline = document.querySelector('.timeline'),
timeInfo = document.getElementById('timeInfo'),
playIcon = `
`,
pauseIcon = `
`,
soundIcon = `
`
function toggleAudio () {
if (audio.paused) {
audio.play();
playerButton.innerHTML = pauseIcon;
} else {
audio.pause();
playerButton.innerHTML = playIcon;
}
}
playerButton.addEventListener('click', toggleAudio);
let isSeeking = false;
// --- Slider (Timeline) events ---
// Mouse events
timeline.addEventListener('mousedown', () => { isSeeking = true; });
timeline.addEventListener('mouseup', () => {
isSeeking = false;
changeSeek(); // Update the audio currentTime based on the slider position
});
timeline.addEventListener('change', changeSeek);
// Touch events
timeline.addEventListener('touchstart', () => { isSeeking = true; });
timeline.addEventListener('touchend', () => {
isSeeking = false;
changeSeek();
});
timeline.addEventListener('touchcancel', () => { isSeeking = false; });
// --- When metadata is loaded, set slider range in seconds ---
audio.addEventListener('loadedmetadata', () => {
updateTimeInfo();
timeline.min = 0;
timeline.max = audio.duration;
timeline.value = 0; // Ensures the thumb starts at the left.
});
// --- Update the slider thumb position (in seconds) while playing ---
function changeTimelinePosition() {
if (!isSeeking) {
timeline.value = audio.currentTime;
const percentagePosition = (audio.currentTime / audio.duration) * 100;
timeline.style.backgroundSize = `${percentagePosition}% 100%`;
}
}
// --- Seek function: directly set audio.currentTime using slider's value (in seconds) ---
function changeSeek() {
audio.currentTime = timeline.value;
}
// --- Utility: Format seconds as mm:ss ---
function formatTime(seconds) {
const minutes = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${minutes < 10 ? '0' : ''}${minutes}:${secs < 10 ? '0' : ''}${secs}`;
}
// --- Update the time display ---
function updateTimeInfo() {
const currentTimeFormatted = formatTime(audio.currentTime);
const durationFormatted = isNaN(audio.duration) ? "00:00" : formatTime(audio.duration);
timeInfo.innerHTML = `${currentTimeFormatted} / ${durationFormatted}`;
}
// --- Update timeline, time info, and media session on each time update ---
audio.ontimeupdate = function() {
changeTimelinePosition();
updateTimeInfo();
if ('mediaSession' in navigator &&
'setPositionState' in navigator.mediaSession &&
!isNaN(audio.duration)) {
navigator.mediaSession.setPositionState({
duration: audio.duration,
playbackRate: audio.playbackRate,
position: audio.currentTime
});
}
};
// --- Also update media session on play (in case timeupdate lags) ---
audio.onplay = function() {
if ('mediaSession' in navigator &&
typeof navigator.mediaSession.setPositionState === 'function' &&
!isNaN(audio.duration)) {
navigator.mediaSession.setPositionState({
duration: audio.duration,
playbackRate: audio.playbackRate,
position: audio.currentTime
});
}
};
// --- Handle external seek requests (e.g. from Android or Windows system controls) ---
if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('seekto', function(details) {
if (details.fastSeek && 'fastSeek' in audio) {
audio.fastSeek(details.seekTime);
} else {
audio.currentTime = details.seekTime;
}
changeTimelinePosition();
});
}
// --- When audio ends ---
audio.onended = function() {
playerButton.innerHTML = playIcon;
};
function downloadAudio() {
// Get the current audio source URL
const audioSrc = audio.currentSrc || audio.src;
if (audioSrc) {
// Create a temporary link element
const a = document.createElement('a');
a.href = audioSrc;
// Extract the file name from the URL, decode it, and set as download attribute
let fileName = audioSrc.split('/').pop() || 'audio';
fileName = decodeURIComponent(fileName);
a.download = fileName;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}