How to make custom audio player applicable to multiple audio? - javascript

I have multiple HTML audio on my page, and want to apply this custom audio player to them. The thing is, this only works for the first audio, and not for the second, third and fourth. Is there any way where I can solve this problem?
My JavaScript code:
const audio = document.getElementById('audio');
const playPauseButton = document.querySelector('.play-button');
const progressBar = document.querySelector('.progress-bar');
const progress = document.querySelector('.progress-controls');
const playButton = document.querySelector('.playing');
const pauseButton = document.querySelector('.paused');
const playPause = () => {
if(audio.paused){
audio.play()
playButton.style.display = 'none';
pauseButton.style.display = '';
}
else{
audio.pause()
playButton.style.display = '';
pauseButton.style.display = 'none';
}
}
function pause(){
pauseButton.style.display = 'none'
}
window.addEventListener('load', pause);
playPauseButton.addEventListener('click', playPause);
audio.addEventListener('timeupdate', function(){
var progress = audio.currentTime / audio.duration;
progressBar.style.width = progress * 100 + "%";
});
document.addEventListener('keyup', (event) => {
if (event.code === 'Space') {
playPause();
}
if (event.code === 'KeyP') {
playPause();
}
});

Related

JavaScript: How can I set src in the JavaScript code based on data attributes in the HTML code?

I want to use 6 of these Before/After Audio Players on my website: https://github.com/mattbartley/AB-Audio-Player
However, the sources of the audio files are set in the JavaScript code. So when I implement multiple instances of this player in my HTML, they all play the same two audio files. I want to set data attributes in the HTML code in each player div for the src of the files and let the JavaScript use that instead. How do I go about it?
<div class="player__wrapper" data-audio-before="Song-1-before.mp3" data-audio-after="Song-1-after.mp3">
...
<div class="player__wrapper" data-audio-before="Song-2-before.mp3" data-audio-after="Song-2-after.mp3">
...
And so on. This would be the updated HTML code.
I think it's a pretty basic solution, I'm just not good in JavaScript.
Here is the current JavaScript code:
//Set up audio elements
var soundA = document.createElement("audio");
//Set audio A src here
soundA.src = "./assets/a.mp3";
soundA.preload = "auto";
soundA.setAttribute("hidden", "true");
soundA.setAttribute("onplaying", "stepA()");
document.body.append(soundA);
var soundB = document.createElement("audio");
//Set audio B src here
soundB.src = "./assets/b.mp3";
soundB.preload = "auto";
soundB.setAttribute("hidden", "true");
soundB.setAttribute("onplaying", "stepB()");
document.body.append(soundB);
I tried something like this: Hover over div, use its data-attribute to change the src of an img
And other approaches as well.
Couldn't get it to work.
I forked the
Matt Bartley 's AB-Audio-Player - not great but it works with multiple instances:
As commented, the player initialization is done within a forEach loop.
All elements are selected by class names to avoid non unique IDs and relative element selection.
So you need to update your HTML template accordingly.
let players = document.querySelectorAll(".player__wrapper");
initPlayers(players);
function initPlayers(players) {
players.forEach((player) => {
//Get button elements
const playBtns = player.querySelectorAll(".ab__button");
const aButton = player.querySelector(".a__button");
const bButton = player.querySelector(".b__button");
const playButton = player.querySelector(".play__button");
const stopButton = player.querySelector(".stop__button");
const progressBar = player.querySelector(".progress__bar");
const progressFill = player.querySelector(".progress__fill");
// set icons
const playIcon = '<i class="fa-solid fa-play"></i>';
const pauseIcon = '<i class="fa-solid fa-pause"></i>';
const stopIcon = '<i class="fa-solid fa-stop"></i>';
//Default loading state for each sound
var soundAReady = false;
var soundBReady = false;
//Set up audio elements
var soundA = document.createElement("audio");
soundA.src = player.getAttribute("data-sound-a");
soundA.preload = "auto";
soundA.setAttribute("hidden", "true");
player.append(soundA);
var soundB = document.createElement("audio");
soundB.src = player.getAttribute("data-sound-b");
soundB.preload = "auto";
soundB.setAttribute("hidden", "true");
player.append(soundB);
//playSoundA
aButton.addEventListener("click", (e) => {
pauseAll();
playButton.innerHTML = pauseIcon;
aButton.disabled = true;
bButton.disabled = false;
stopButton.disabled = false;
soundA.currentTime = soundB.currentTime;
soundA.play();
});
//playSoundB
bButton.addEventListener("click", (e) => {
pauseAll();
playButton.innerHTML = pauseIcon;
bButton.disabled = true;
aButton.disabled = false;
stopButton.disabled = false;
soundB.currentTime = soundA.currentTime;
soundB.play();
});
//playSoundA
soundA.addEventListener("playing", (e) => {
console.log("playing");
progressFill.style.width =
((soundA.currentTime / soundA.duration) * 100 || 0) + "%";
requestAnimationFrame(stepA);
});
//playSoundB
soundB.addEventListener("playing", (e) => {
console.log("playing B");
progressFill.style.width =
((soundB.currentTime / soundB.duration) * 100 || 0) + "%";
requestAnimationFrame(stepB);
});
// playPause
playButton.addEventListener("click", (e) => {
if (soundA.paused & soundB.paused) {
let soundATime = soundA.currentTime;
let soundBTime = soundB.currentTime;
if (soundATime >= soundBTime) {
soundA.play();
bButton.disabled = false;
aButton.disabled = true;
playButton.innerHTML = pauseIcon;
} else {
soundB.play();
bButton.disabled = true;
aButton.disabled = false;
playButton.innerHTML = pauseIcon;
}
stopButton.disabled = false;
} else {
playButton.innerHTML = playIcon;
soundA.pause();
soundB.pause();
}
});
// stop
stopButton.addEventListener("click", (e) => {
playButton.innerHTML = playIcon;
aButton.disabled = false;
bButton.disabled = true;
playButton.disabled = false;
stopButton.disabled = true;
soundA.pause();
soundA.currentTime = 0;
soundB.pause();
soundB.currentTime = 0;
});
//Check for mobile to enable audio playback without waiting for download status.
if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
)
) {
playButton.disabled = false;
}
//Default loading state for each sound
var soundAReady = false;
var soundBReady = false;
//When audio can play through (loaded), run the function to enable buttons
//The canplaythrough event will fire every time the audio switches, so the !soundA/BReady
//prevents additional checks
soundA.oncanplaythrough = function() {
if (!soundAReady) {
soundAReady = true;
audioIsReady();
}
};
soundB.oncanplaythrough = function() {
if (!soundBReady) {
soundBReady = true;
audioIsReady();
}
};
// Check if both A & B are ready and enable the correct buttons
function audioIsReady() {
if (soundAReady && soundBReady) {
console.log("...audio loaded!");
aButton.disabled = false;
playButton.disabled = false;
} else {
console.log("Audio loading...");
}
}
const progress = player.querySelector(".progress");
// Listen for click on entire progress bar div (to allow skipping ahead)
progress.addEventListener("click", function(event) {
// Get X coordinate of click in div
var rect = this.getBoundingClientRect();
// Convert click position to percentage value
var percentage = (event.clientX - rect.left) / this.offsetWidth;
// Seek to the percentage converted to seconds
soundA.currentTime = percentage * soundA.duration;
soundB.currentTime = percentage * soundB.duration;
});
//Frame animations for progress bar fill - converts to CSS percentage
function stepA() {
progressFill.style.width =
((soundA.currentTime / soundA.duration) * 100 || 0) + "%";
requestAnimationFrame(stepA);
}
function stepB() {
progressFill.style.width =
((soundB.currentTime / soundB.duration) * 100 || 0) + "%";
requestAnimationFrame(stepB);
}
//Play/Stop correct audio and toggle A/B, Play/Pause, and Stop buttons
function playPause() {
if (soundA.paused & soundB.paused) {
let soundATime = soundA.currentTime;
let soundBTime = soundB.currentTime;
if (soundATime >= soundBTime) {
soundA.play();
bButton.disabled = false;
aButton.disabled = true;
playButton.innerHTML = pauseIcon;
} else {
soundB.play();
bButton.disabled = true;
aButton.disabled = false;
playButton.innerHTML = pauseIcon;
}
stopButton.disabled = false;
} else {
playButton.innerHTML = playIcon;
soundA.pause();
soundB.pause();
}
}
// optional: set auto ids
let allAudio = document.querySelectorAll("audio");
allAudio.forEach((audio, i) => {
audio.id = "audio_" + i;
});
// rewind all at end
allAudio.forEach((audio) => {
//audio.pause();
audio.addEventListener("ended", (e) => {
audio.currentTime = 0;
progressFill.style.width = "0%";
});
});
function pauseAll() {
let allAudio = document.querySelectorAll("audio");
allAudio.forEach((audio) => {
audio.pause();
});
}
});
}
<link href="https://fonts.googleapis.com/css2?family=Lato:wght#400;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player#main/css/style.css" />
<div class="player__wrapper" data-sound-a="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player#main/assets/a.mp3" data-sound-b="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player#main/assets/b.mp3">
<div class="progress__container progress">
<div class="progress__bar progress__fill"></div>
</div>
<div class="ab__controls">
<button class="ab__button a__button" disabled="true">
A
</button>
<button class="ab__button b__button" disabled="true">
B
</button>
</div>
<div class="play__stop__controls">
<button class="play__pause__button play__button" disabled="true">
<i class="fa-solid fa-play"></i>
</button>
<button class="play__pause__button stop__button" disabled="true">
<i class="fa-solid fa-stop"></i>
</button>
</div>
</div>
<div class="player__wrapper" data-sound-a="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player#main/assets/a.mp3" data-sound-b="https://cdn.jsdelivr.net/gh/mattbartley/AB-Audio-Player#main/assets/b.mp3">
<div class="progress__container progress">
<div class="progress__bar progress__fill"></div>
</div>
<div class="ab__controls">
<button class="ab__button a__button" disabled="true">
A
</button>
<button class="ab__button b__button" disabled="true">
B
</button>
</div>
<div class="play__stop__controls">
<button class="play__pause__button play__button" disabled="true">
<i class="fa-solid fa-play"></i>
</button>
<button class="play__pause__button stop__button" disabled="true">
<i class="fa-solid fa-stop"></i>
</button>
</div>
</div>
According to MDN, firstly you should change your HTML a bit and add id to your elements:
<div id="player-1" class="player__wrapper" data-audio-before="Song-1-before.mp3" data-audio-after="Song-1-after.mp3">
Then you can access your data-audio attribute from your JS code thorough dataset object:
//Set up audio elements
var soundA = document.createElement("audio");
//bring div element to your code
const playerA = document.querySelector("#player-1")
//Set audio A src here
soundA.src = playerA.dataset.dataAudioBefore;
soundA.preload = "auto";
soundA.setAttribute("hidden", "true");
soundA.setAttribute("onplaying", "stepA()");
document.body.append(soundA);
var soundB = document.createElement("audio");
//Set audio B src here
soundB.src = playerA.dataset.dataAudioAfter;
soundB.preload = "auto";
soundB.setAttribute("hidden", "true");
soundB.setAttribute("onplaying", "stepB()");
document.body.append(soundB);
hope this helps!
This is actually a comment on your answer, but duo to StackOverflow policy, I couldn't comment directly!
Anyway, I think your problem is that you are using querySelectorAll with classes.
Have you tried using id in your HTML element and using querySelector("#id") in your JS code?
In addition, please vote me up/check correct answer if it helps!
I got it working somewhat with some help from ChatGPT:
const players = document.querySelectorAll('.player__wrapper');
var soundA, soundB;
players.forEach(player => {
soundA = document.createElement("audio");
soundA.src = player.dataset.audioBefore;
soundA.preload = "auto";
soundA.setAttribute("hidden", "true");
soundA.setAttribute("onplaying", "stepA()");
document.body.append(soundA);
soundB = document.createElement("audio");
soundB.src = player.dataset.audioAfter;
soundB.preload = "auto";
soundB.setAttribute("hidden", "true");
soundB.setAttribute("onplaying", "stepB()");
document.body.append(soundB);
});
It works when I only have one audio player. When I use two, the first one uses the audio files which I put in the second one and the second one doesn't work at all.
Anyone got an idea? Maybe the rest of the JS code is relevant too, here it is:
//Get button elements
const aButton = document.getElementById("a__button");
const bButton = document.getElementById("b__button");
const playButton = document.getElementById("play__button");
const stopButton = document.getElementById("stop__button");
const progressBar = document.getElementById("progress__bar");
const progressFill = document.getElementById("progress__fill");
const playIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M3 22v-20l18 10-18 10z"/></svg>';
const pauseIcon = '<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd"><path d="M10 24h-6v-24h6v24zm10 0h-6v-24h6v24zm-11-23h-4v22h4v-22zm10 0h-4v22h4v-22z"/></svg>';
const stopIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M2 2h20v20h-20z"/></svg>';
//Check for mobile to enable audio playback without waiting for download status.
if (
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent
)
) {
playButton.disabled = false;
}
//Default loading state for each sound
var soundAReady = false;
var soundBReady = false;
//When audio can play through (loaded), run the function to enable buttons
//The canplaythrough event will fire every time the audio switches, so the !soundA/BReady
//prevents additional checks
soundA.oncanplaythrough = function () {
if (!soundAReady) {
soundAReady = true;
audioIsReady();
}
};
soundB.oncanplaythrough = function () {
if (!soundBReady) {
soundBReady = true;
audioIsReady();
}
};
// Check if both A & B are ready and enable the correct buttons
function audioIsReady() {
if (soundAReady && soundBReady) {
console.log("...audio loaded!");
aButton.disabled = false;
playButton.disabled = false;
} else {
console.log("Audio loading...");
}
}
const progress = document.getElementById("progress");
// Listen for click on entire progress bar div (to allow skipping ahead)
progress.addEventListener("click", function (event) {
// Get X coordinate of click in div
var rect = this.getBoundingClientRect();
// Convert click position to percentage value
var percentage = (event.clientX - rect.left) / this.offsetWidth;
// Seek to the percentage converted to seconds
soundA.currentTime = percentage * soundA.duration;
soundB.currentTime = percentage * soundB.duration;
});
//Frame animations for progress bar fill - converts to CSS percentage
function stepA() {
progressFill.style.width =
((soundA.currentTime / soundA.duration) * 100 || 0) + "%";
requestAnimationFrame(stepA);
}
function stepB() {
progressFill.style.width =
((soundB.currentTime / soundB.duration) * 100 || 0) + "%";
requestAnimationFrame(stepB);
}
//Play/Stop correct audio and toggle A/B, Play/Pause, and Stop buttons
const playPause = () => {
if (soundA.paused & soundB.paused) {
let soundATime = soundA.currentTime;
let soundBTime = soundB.currentTime;
if (soundATime >= soundBTime) {
soundA.play();
bButton.disabled = false;
aButton.disabled = true;
playButton.innerHTML = pauseIcon;
} else {
soundB.play();
bButton.disabled = true;
aButton.disabled = false;
playButton.innerHTML = pauseIcon;
}
stopButton.disabled = false;
} else {
playButton.innerHTML = playIcon;
soundA.pause();
soundB.pause();
}
};
const playSoundA = () => {
playButton.innerHTML = pauseIcon;
aButton.disabled = true;
bButton.disabled = false;
stopButton.disabled = false;
if (soundB.currentTime > 0) {
soundA.currentTime = soundB.currentTime;
soundA.play();
soundB.pause();
} else {
soundA.play();
soundB.pause();
}
};
const playSoundB = () => {
playButton.innerHTML = pauseIcon;
bButton.disabled = true;
aButton.disabled = false;
stopButton.disabled = false;
if (soundA.currentTime > 0) {
soundB.currentTime = soundA.currentTime;
soundB.play();
soundA.pause();
} else {
soundB.play();
}
};
const stopSounds = () => {
playButton.innerHTML = playIcon;
aButton.disabled = false;
bButton.disabled = true;
playButton.disabled = false;
stopButton.disabled = true;
soundA.pause();
soundA.currentTime = 0;
soundB.pause();
soundB.currentTime = 0;
};

JavaScript: how to stop an audio on autoplay by keyboard

I want to know how to stop an audio that is set to "autoplay" using the X key on the keyboard. I have tried in a couple of method but it doesn't work.
That's my code:
JavaScript:
var source = "audio/homepage_benvenuto.mp3";
var audio = document.createElement("audio");
audio.autoplay = true;
audio.load()
audio.addEventListener("load", function()
{
audio.play();
}, true);
audio.src = source;
window.addEventListener("keydown", checkKeyPressed, false);
function checkKeyPressed(e)
{
if (e.keyCode == "88") // 88 = X: interrompe audio in corso
{
player.pause();
player.currentTime = 0;
document.getElementById('audioA').pause();
}
}

how to make play/pause button

I would like the pause button to resume the song from where it was paused instead of restarting the song.
with vanilla javascript only please,
Thank you !
var songs = [
"song1.mp3",
"song2.mp3",
"song3.mp3",
];
var song = new Audio();
var currentSong = 0;
var playButton = document.querySelector(".play");
var pauseButton = document.querySelector(".pause");
function playSong() {
song.src = songs[currentSong];
pauseButton.style.display = "block";
playButton.style.display = "none";
songTitle.textContent = sT[currentSong];
Artist.textContent = artistNames[currentSong];
songCover.src = songCovers[currentSong];
song.play();
}
playButton.addEventListener("click", function playSong() {
song.src = songs[currentSong];
pauseButton.style.display = "block";
playButton.style.display = "none";
songTitle.textContent = sT[currentSong];
Artist.textContent = artistNames[currentSong];
songCover.src = songCovers[currentSong];
song.play();
});
pauseButton.addEventListener("click", function pauseSong() {
song.pause();
pauseButton.style.display = "none";
playButton.style.display = "block";
});
The song resets because every time you click on the play button, the src of the song is being assigned again. And therefor the song will start over from the start.
So you'll need to change the part of your code where the song is selected. Do that outside of the play function so that clicking play will only play, and clicking pause will only pause.
function chooseSong() {
song.src = songs[currentSong];
songTitle.textContent = sT[currentSong];
Artist.textContent = artistNames[currentSong];
songCover.src = songCovers[currentSong];
}
function playSong() {
pauseButton.style.display = "block";
playButton.style.display = "none";
song.play();
}
function pauseSong() {
pauseButton.style.display = "none";
playButton.style.display = "block";
song.pause();
}
playButton.addEventListener('click', playSong);
pauseButton.addEventListener('click', pauseSong);
chooseSong();

How to make custom video player applicable to multiple videos?

I have multiple HTML videos on my page, and want to apply this custom video player to them. The thing is, this only works for the first video, and not for the second, third and fourth.
I have no idea where to start.
I made a fiddle of the current state: JSFiddle
My Javascript
/* Get Our Elements */
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const toggle = player.querySelector('.toggle');
const skipButtons = player.querySelectorAll('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');
/* Build out functions */
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
function updateButton() {
const icon = this.paused ? '►' : '❚❚';
toggle.textContent = icon;
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
video[this.name] = this.value;
}
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
/* Hook up the event listners */
video.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
toggle.addEventListener('click', togglePlay);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
$('video').on('ended', function() {
$.fn.fullpage.moveSlideRight();
});
I want this script to work on every video element on the page:
JSFiddle
Thanks,
Max
You can try something like this :
/* Get Our Elements */
$('.player').each(function() {
var player = $(this).get(0);
var video = player.querySelector('.viewer');
var progress = player.querySelector('.progress');
var progressBar = player.querySelector('.progress__filled');
var toggle = player.querySelector('.toggle');
var skipButtons = player.querySelectorAll('[data-skip]');
var ranges = player.querySelectorAll('.player__slider');
/* Build out functions */
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
function updateButton() {
const icon = this.paused ? '►' : '❚❚';
toggle.textContent = icon;
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
video[this.name] = this.value;
}
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
/* Hook up the event listners */
video.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
toggle.addEventListener('click', togglePlay);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
$('video').on('ended', function() {
$.fn.fullpage.moveSlideRight();
});
});
https://jsfiddle.net/kq5hdw0m/

Javascript display image on audio current time

im just a beginner in javascript and im stuck at a problem.
when i click play with function play()
it shows if its <= 2.5 but not when its > 2.5 .(I displayed the 'reddot' in html as display hidden).
function play() {
var audio = document.getElementById("audio");
audio.play();
if (audio.currentTime <= 2.5) {
document.getElementById('reddot').style.display = 'block';
}
if (audio.currentTime > 2.5) {
document.getElementById('reddot').style.display = 'none';
document.getElementById('reddot2').style.display = 'block';
}
}
function () {
}
function pause(){
var audio = document.getElementById("audio");
audio.pause();
}
function load(){
var audio = document.getElementById("audio");
audio.pause();
audio.currentTime = 0;
}
function rewind() {
var audio = document.getElementById("audio");
audio.play();
audio.currentTime = (audio.currentTime-6);
}

Categories

Resources