I have the following script which gets all video elements on a given page and then applies a playing event to them:
var video = document.getElementsByTagName("video");
for(var i = 0; i < video.length; i++){
(function(vid) {
vid.addEventListener('playing', function(){
var percentComplete = Math.round((vid.currentTime / vid.duration) * 100);
console.log(percentComplete);
});
})
(video[i]);
}
Now when I run the page and click on video 1 for example I see the percentComplete being logged to the console log, however when video 1 finishes and I click video 2 nothing is written to the console, it seems this addEventListener is only applied to the first video that is clicked, can someone explain why and how I can resolve this so it fires every time a video is played?
Try removing the outer closure and using event.target within your listener.
var video = document.getElementsByTagName("video");
for (var i = 0; i < video.length; i++) {
video[i].addEventListener('playing', function (event) {
var vid = event.target
var progress = Math.round((vid.currentTime / vid.duration) * 100)
console.log(progress)
})
}
For anyone interested, here's the full list of media events.
Related
Upong calling audioElement.duraion returns infinite in chromium based browsers but works find in firefox. The song is stored locally in the same directory.
console.log("Welcome to Spotify | clone");
let songIndex = 0;
const masterPlay = document.getElementById("masterPlay");
const progressBar = document.getElementById("progressBar");
const gif = document.getElementById("gif");
const audioElement=document.getElementById("song")
// let audioElement=new Audio('./1.mp3')
// Handeling play pause and click
masterPlay.addEventListener('click', () => {
if (audioElement.paused || audioElement.currentTime <= 0) {
audioElement.play();
masterPlay.classList.remove("fa-circle-play");
masterPlay.classList.add("fa-circle-pause");
gif.style.opacity = 1;
}
else {
audioElement.pause();
masterPlay.classList.remove("fa-circle-pause");
masterPlay.classList.add("fa-circle-play");
gif.style.opacity = 0;
}
});
//EventListeners
audioElement.addEventListener("timeupdate", () => {
progress = ((audioElement.currentTime / audioElement.duration) * 100);
progressBar.value = progress;
console.log(audioElement.currentTime)
});
Expectations:
It returns the duration of the autio track.
What I tried:
Different browsers. (Works fine on firefox based browsers.)
Different song. (I found that some songs don't work on chrome but on firefox everything works.)
Tried using HTML audio element. (The problem persists)
Tried using JS audio(). (The problem still exists)
At the end of the day I found out that it was a bug with VS code Live Preview extension from Microsoft
I have an HTML page that loads a video and display a download progress bar.
The video element is created like this:
function createVideo() {
var video = document.createElement("VIDEO");
video.setAttribute('controls', '');
video.setAttribute('preload', 'auto');
video.setAttribute('width', width);
video.setAttribute('id', 'video');
var source = document.createElement("SOURCE");
source.setAttribute('src', "https://www.example.com/video.mp4");
source.setAttribute('type', 'video/mp4');
video.addEventListener('progress', function() {
var endBuf = this.buffered.end(0); //1
var soFar = parseInt(((endBuf / this.duration) * 100));
var progressBar = document.getElementById("progressBar");
if (soFar < 100) {
progressBar.setAttribute('value', soFar);
} else {
progressBar.style = "display:none;";
}
});
The behavior I have on browsers is like this:
Safari shows the video page but the video does not auto play. No error is shown on console.
Firefox autoplays the video and shows no error on console.
Chrome autoplays the video and shows this error on console:
2codes.js:368 Uncaught DOMException: Failed to execute 'end' on 'TimeRanges': The index provided (0) is greater than or equal to the maximum bound (0).
at HTMLVideoElement. (https://example.com/code.js:368:32)
(anonymous) # functions.js:368
Line 368 is the one marked with //1 on the code above.
How do I solve that?
It's possible that Chrome is triggering your "progress" listener before the video is completely loaded and meaning that this.buffered has no TimeRanges yet. You might consider wrapping the body of your "progress" listener in an statement to handle if buffered has no TimeRanges specified:
video.addEventListener('progress', function() {
if(this.buffered.length > 0) {
var endBuf = this.buffered.end(0);
var soFar = parseInt(((endBuf / this.duration) * 100));
var progressBar = document.getElementById("progressBar");
if (soFar < 100) {
progressBar.setAttribute('value', soFar);
} else {
progressBar.style = "display:none;";
}
} else {
progressBar.style = "display:none;";
}
});
I'm building a CMS site for a client who'll be uploading videos. I'm trying to build a custom progress bar for each video too, I've done this before but there was only one video present so I could use a getElementByID to call each video, but as there's going to be multiple videos per page I tried to call an each function and find each element by it's class within it's parent container.
You can see my codepen here: https://codepen.io/neal_fletcher/pen/JJzbYP
As you can see though the progress bar isn't moving when the video plays (as it should), there's only one video here but there will be multiple videos so I CANT use a function that relies on ID's of each element.
My jQuery markup below too:
window.onload = function() {
$(".video-wrap").each(function() {
var slideshowVideo = document.getElementsByClassName("homepage-video");
var slideshowSeek = document.getElementsByClassName("seek-bar");
slideshowSeek.addEventListener("change", function() {
// Calculate the new time
var time = slideshowVideo.duration * (slideshowSeek.value / 100);
// Update the video time
slideshowVideo.currentTime = time;
});
});
Any suggestions on the best solution for this would be greatly appreciated!
Working code
window.onload = function() {
$(".video-wrap").each(function() {
var slideshowVideo = document.getElementsByClassName("homepage-video");
var slideshowSeek = document.getElementsByClassName("seek-bar");
slideshowSeek[0].addEventListener("change", function() {
// Calculate the new time
var time = slideshowVideo.video.duration * (slideshowSeek[0].value / 100);
// Update the video time
slideshowVideo.video.currentTime = time;
});
slideshowVideo.video.addEventListener('timeupdate', function(video){
slideshowSeek[0].value = slideshowVideo.video.currentTime * 100 / slideshowVideo.video.duration;
}, false);
});
}
check below pen
https://codepen.io/anon/pen/qjvRXP?editors=0110
In an English/Thai language web page, I've got 4 columns of English phrases with associated audio files. A phrase from each column is selected by mouse click. After 4 phrases have been selected, I want their audio files to play sequentially. Here is 1 of 4 segments of code doing the selection (they differ only in html tags selection and localStorage locations).These work OK.
var audioIsPlaying = false;
jQuery("div#wh_set1").on("click", "p span", function (evnt) {
var elementId = evnt.target.id,
word1 = jQuery(this).text();
jQuery("span#word1").html(word1);
var pathVar = document.getElementById("pathVar").innerHTML,
oggVar = pathVar+elementId+".ogg",
mp3Var = pathVar+elementId+".mp3";
if(Modernizr.audio.ogg) {
localStorage.setItem("wh_set1", oggVar);
}else {
localStorage.setItem("wh_set1", mp3Var);
}
});
Sequential playback of the audio files is intended to be handled by the following code:
var currentAudio = document.createElement('audio'), i ;
function audioPlay(i) {
audioIsPlaying = false;
currentAudio.setAttribute("src", localStorage.getItem('wh_set' + i));
currentAudio.load();
currentAudio.play();
audioIsPlaying = true;
// alert("wh_set" +i);
}
for(i = 1; i <= 4; i++) {
currentAudio.addEventListener("ended", audioPlay(i));
}
But this does not work as intended. Only the audio file of the last of the 4 selected phrases plays. If the alert is uncommented then each selection plays in the correct sequence. Similarly, if the code is stepped thru with Firebug, then the audio files play in correct sequence.
I've had a look at previous posts on audio file sequencing but I could see anything directly applicable. Any help would be much appreciated.
The problem is: you don't add function to event ended, you call it immediatly.
Your code do this:
audioPlay(1);
audioPlay(2);
audioPlay(3);
audioPlay(4);
The first three audios don't have a chance to load and start.
I replaced
for(i = 1; i <= 4; i++) {
currentAudio.addEventListener("ended", audioPlay(i));
}
to
var i = 1;
currentAudio.addEventListener( "ended", function() {
i++;
if ( i < 5 ) {
audioPlay( i );
}
} );
audioPlay( 1 );
and it works perfectly in Chrome and Firefox
In an attempt to overcome Google TTS API's character limit of 100 chars, tried to loop every 100 characters to fetch a fresh mp3 from the api and play seamlessly. Tried multiple ways, but the .play() and the event listeners like canplay/onended doesn't just seem to work inside a loop!
Best that could be achieved is to get all the downloaded tracks to play simultaneously, rather than one after the other. Below is some code :-
if ($("#theinput").attr("value").length > 100){
var len = $("#theinput").attr("value").length;
alert(len);
var audioPlayer = document.getElementById("spokenmemory");
for (var i=0; i < (len / 100); i++) {
var stl=i*100;
var str = $("#theinput").attr("value").substr(stl, 100);
$("#spokenmemory").attr("src", "http://translate.google.com/translate_tts? tl=en&q="+str);
alert(str);
audioPlayer.load();
audioPlayer.addEventListener('canplay', function () {
alert('Loaded');
audioPlayer.play();
} );
//audioPlayer.play();
}
Any help will be appreciated.
Try to use the trigger function instead
fadeInAudio : function(audio){
// audio.play();
audio.trigger("play");
},
fadeOutAudio : function(audio){
// audio.pause();
audio.trigger("pause");
},