Can you tell me how to start a HTML5 video after it loaded a certain amount? For example if i have a 10 second video and i want it to start only when it loaded at least 5 seconds. How can i determine when that happenes?
Edit: We assume that the video is loading and it is in a .pause() position not in .stop()
You can read the buffered property of the video element to see what time ranges have been loaded. The buffered property is a collection of time ranges that have been loaded; you can read the start and end of the nth range with buffered.start(n) and buffered.end(n). Since you're interested in the end-time of the first range, you can read the number of seconds loaded on some video videoElm with videoElm.buffered.end(0).
A <video> element fires progress events to indicate that it has loaded a new chunk of data (and consequently that the end time of some time range in buffered is increasing).
You can check if your loaded buffer is big enough after each progress event:
var someVideo = document.getElementById("myVideoId");
someVideo.addEventListener("progress", function playOnLoad(e) {
var theVideo = e.target;
if(theVideo.buffered.length > 0 && // if we have a buffer
theVideo.buffered.end(0) >= 5) { // if first buffer is at least 5 secs
theVideo.play();
theVideo.removeEventListener(playOnLoad);
}
});
If you're actually interested in whether the video can safely play through without interruption, the browser uses the canplaythrough event. The browser will fire this event when it predicts that the loading rate of the video will allow it to play through without interruption (but it may sometimes be wrong, if the loading rate suddenly changes).
I don't believe this is possible since every browser has it's own measurement in seconds when a video is ready to be played e.g. the browser controls the buffer load.
The preload attribute on the video element gives you some form of control, but not in seconds and not cross-browser consistent.
Check the table on this page.
I'm not sure why you would control this. The only thing you should be worried about is if the video can play through.
this.video.on('canplaythrough', function () {
this.video[0].play();
}.bind(this));
If for some reason you need to capture an event earlier check this page for other events.
Related
If all of these work, which would be the best one to use here?
canplay, canplaythrough, playing, or play
Would it make sense to only use one of them, and if so, which one?
Would it make sense to use all of them?
const playingEvents = ["playing"];
Code: https://jsfiddle.net/spaozyxq/28/
Sent when the media has enough data to start playing, after the play
event, but also when recovering from being stalled, when looping media
restarts, and after seeked, if it was playing before seeking.
const playingEvents = ["canplaythrough"];
Code: https://jsfiddle.net/spaozyxq/30/
The user agent estimates that if playback were to be started now, the
media resource could be rendered at the current playback rate all the
way to its end without having to stop for further buffering.
const playingEvents = ["canplay"];
Code: https://jsfiddle.net/spaozyxq/32/
The user agent can resume playback of the media data, but estimates
that if playback were to be started now, the media resource could not
be rendered at the current playback rate up to its end without having
to stop for further buffering of content.
const playingEvents = ["play"];
Code: https://jsfiddle.net/spaozyxq/36/
Sent when the playback state is no longer paused, as a result of the
play method, or the autoplay attribute.
const playingEvents = ["canplay", "canplaythrough", "play", "playing"];
Code: https://jsfiddle.net/spaozyxq/39/
I have been trying to create my custom media player using HTML5 and Jquery.
I have followed different approaches and ran into some trouble based on my way of refreshing the page.
First Case
$(document).ready(function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
In this case, the duration returns NaN when I redirect the page to the same URL by pressing the ENTER key in the address bar. However, it works completely fine when I refresh using the reload button or by pressing the F5 button.
Second Case
I read in some answers that loading duration after the loadedmetadataevent might help. So I tried the following:
$(document).ready(function(){
$('audio').on('loadedmetadata', function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
});
Surprisingly, in this case, the inverse of the first case happened. The duration gets displayed completely fine in the case of a redirect, i.e., pressing ENTER while in the address bar. However, in the case of refreshing using the F5 button or the reload button, the duration doesn't get displayed at all, not even NaN which led me to believe that the code doesn't get executed at all.
Further reading suggested this might be a bug within the webkit browsers but I couldn't find anything conclusive or helpful.
What could be the cause behind this peculiar behavior?
It'd be great if you could explain it along with the solution to this problem.
Edit:
I am mainly looking for an explanation behind this difference in behavior. I would like to understand the mechanism behind rendering a page in the case of redirect and refresh.
It sounds like the problem is that the event handler is set too late, i.e. the audio file has loaded its metadata before the document is even ready.
Try setting the event handler as soon as possible by removing the $(document).ready call:
$('audio').on('loadedmetadata', function(){
duration = Math.ceil($('audio')[0].duration);
$('#duration').html(duration);
});
Note that this requires that the <script> tag be after the <audio> tag in the document.
Alternatively, you can tweak your logic slightly, so that the code that updates the duration always runs (but fails gracefully if it gets a NaN):
function updateDuration() {
var duration = Math.ceil($('audio')[0].duration);
if (duration)
$('#duration').html(duration);
}
$(document).ready(function(){
$('audio').on('loadedmetadata', updateDuration);
updateDuration();
});
Lovely code examples and stuff from people - but the explanation is actually very simple.
If the file is already in the cache then the loadedmetadata event will not fire (nor will a number of other events - basically because they've already fired by the time you attach your listeners) and the duration will be set. If it's not in the cache then the duration will be NaN, and the event will fire.
The solution is sort of simple.
function runWhenLoaded() { /* read duration etc, this = audio element */ }
if (!audio.readyState) { // or $audio[0].readyState
audio.addEventListener("loadedmetadata", runWhenLoaded);
// or $audio.on("loadedmetadata", runWhenLoaded);
} else {
runWhenLoaded.call(audio);
// or runWhenLoaded.call($audio[0]);
}
I've included the jQuery alternatives in the code comments.
According to w3 spec this is standard behavior when duration returns NaN.
So I suggest use durationchange event:
$('audio').on('durationchange', function(){
var duration = $('audio')[0].duration;
if(!isNaN(duration)) {
$('#duration').html(Math.ceil(duration));
}
});
NOTE: This code (and your too) will not work correct in case if you have more than one audio element on page. Reason is that you listen events from all audio elements on page and each element will fire own event:
$('audio').on('durationchange', function(){...});
OR
You can try:
<script>
function durationchange() {
var duration = $('audio')[0].duration;
if(!isNaN(duration)) {
$('#duration').html(Math.ceil(duration));
}
}
</script>
<audio ondurationchange="durationchange()">
<source src="test.mp3" type="audio/mpeg">
</audio>
Note that behaviors will differ from one browser to another. On Chrome, you have different type of loading. When resources are not in cache, it will fetch either the complete file (for js or css for example), either a part of the file (mp3 for example). This partial file contains metadata that allows browser to determine duration and other data such as the time it'll take to download whole file at this rate, trigerring for example canplay or canplaythrough events. If you look at network usage in you dev console, you'll see that the HTTP status code will be either 200 (succesful load) or 206(partial load - for mp3 for example).
When you hit refresh, elements are checked to see if they changed. HTTP status will then be 304, meaning file hasn't been modified. If it hasn't changed and is still in browser cache, then it won't be downloaded. The call to determine if it has or not changed comes from the server providing the file.
When ou simply click enter in adress bar, it's automatically taken from cache, not validating online. So it's much faster.
So depending on how you call or refresh your page (either simmple enter, refresh or complete refresh without cache), you'll have big differences on the moment you get the metadata from your mp3. Between taking the metadata from cache directly vs making a request to a server, the difference can be a few hundreds milliseconds, which is enough to change what data is available at different moment.
That being said, listening to loadedmetada should give consistent result. This event is triggered when the data with duration information is loaded, so whatever way the page is loaded, it shouldn't matter if that called is properly made. At this point you have to consider maybe some interference from other elements. What you should do is follow your audio through various events to get exactly where its at at different moments. So in you document ready you could add listeners for different event and see where the problem occurs. Like this:
$('audio')[0].addEventListener('loadstart', check_event)
$('audio')[0].addEventListener('loadeddata', check_event)
$('audio')[0].addEventListener('loadedmetadata', check_event)//at this point you should be able to call duration
$('audio')[0].addEventListener('canplay', check_event) //and so on
function check_event(e) {
console.log(e.target, e.type)
}
You'll see that depending on the way you refresh, these events can come at different moments, maybe explaining inconsistencies in your outputs.
I need to trigger a piece of code after every single bits are done downloading. The script works if injected after everything is loaded, but how do I trigger that automaticly?
My script is:
var divId = "jwplayer-0_wrapper";
if ($('#' + divId).length == 1) {
myReg = /https?:\/\/www\.youtube\.com\/watch\?v=[^"]+/;
var plainText = $('#' + divId).parent().children('script').text();
var url = plainText.match(myReg);
if (url !== null) {
window.location = url;
};
};
It is used to skip certain site that decide to use the JW player witch I find horribly buggy. So it looks for a div with the indication of the JW player and if there's one, it finds the link to the original youtube video and directly goes there.
Its triggered By Google Chrome Add-on named Javascript Injector and I apply the script on every page I visit. The plug in work perfectly well on sites like www.ayoye.co and www.veuxturire.com. But on other sites, that uses the same pathern, it seems that the script is triggerd too early. For example there www.mondedestars.com and www.lesautos.ca triggers it too early.
If I use the "inject now" fonction of the Add on after the page is really done loading, then it redirects me to the youtube page as expected. I am lost on the why it works some where and not were else.
I'm not trying to understand every single website here, I'd prefer make it dynamicly triggered after the page has done loading everything from its php, ajax, script, flash, html and CSS.
I've tryed to look to the JWplayer API, but since its terribly unclear to me, over the fact that its partialy in flash, it woudl be simpler if there was a way to trigger it after, or maybe just triggering it after i hover over the body, since every sites has a body. It cant be specific to one page.
Use something like this
var timer;
function injectYouTube() {
// DO YOUR STUFF HERE
// ONCE DONE CALL clearInterval(timer);
clearInterval(timer);
}
timer = setInterval(injectYouTube, 2000);
I am not saying this will be called after everything is loaded but instead you can make sure your code is executed when you want it to.
The JWPlayer API are not that difficult. You can retrive the informations you need even not knowing the container id.
This is an example:
var player = jwplayer(0); // get the first jwplayer element of the page
var video = player.getPlaylistItem(); // get the player video
var url = video.file // retrieve the video url
I think the setTimeout or setInterval are unreliable.
Setting up a listener on jwplayer onReady event would be better.
The pessimistic answer to this is that you can't wait until a page has finished all AJAX operations etc. because web pages can continue loading new content indefinitely if they wish.
What you might consider is running your code every time a new HTML element is added to the page. This way, you can be certain to catch JWPlayer the moment it is inserted into the page.
document.addEventListener("DOMNodeInserted", yourRemovalFunction);
I have an absolutely placed div with an embedded YouTube video inside of it. I am placing it over another image on my website with the intention of showing first-time visitors a short video, then hiding the div with the video to reveal the original content of the page.
I know how to hide and show my div with click events, but I am very new to Javascript. I need help writing the function that would determine the YouTube video has ended and apply visibility:hidden to my div. Any help is greatly appreciated!
your going to want to take a careful look at the documentation, paying special attention to the Events section.
you will be using
onStateChange:
This event is fired whenever the player's state changes. Possible values are unstarted (-1), ended (0), playing (1), paused (2),
buffering (3), video cued (5). When the SWF is first loaded it will
broadcast an unstarted (-1) event. When the video is cued and ready to
play it will broadcast a video cued event (5).
and you will want to do something when the state equals 0, which means ended, something similar to the below:
// attach your listener
function onYouTubePlayerReady(playerId) {
var ytplayer = getElementById("myytplayer");
ytplayer.addEventListener("onStateChange", "onytplayerStateChange");
}
// your callback function
function onytplayerStateChange(newState) {
if (newState === 0){
$('yourContainingDiv').hide();
// or if you want to just remove it...
$('yourContainingDiv').remove();
}
}
if you are having trouble with addEventListener, check out YouTube player api - addEventListener() does not work for me?
addEventListener looks like it isn't supported by early versions of IE and might be slightly buggy
I've created a game which has a number of elements on a page,
when the mouseover event on the element is triggered an audio file plays.
Its working, however,
My question is, What is the correct way to preload audio?
So i can be sure that my audio plays as soon as the user interacts with the element.
I'm currently initialsing my audio object on mouseover
$('.circle').mouseover(function() {
// retrieve ref from data- attribute
var noteIndex = $(this).attr('data-note');
// locate url from the array notes using noteIndex ref
var snd = new Audio(notes[noteIndex]);
snd.play();
}
I'm aware of the Audio tags, but i'm unsure how that differs from my technique above.
EDIT : example of how i'm currently loading audio http://jsfiddle.net/kA5Bv/1/ (note the key doesn't play immediately, thats because the example audio files i've used has a gap of 1/2 second or so at the beginning)
Thanks in advance,
Cam
What about the $(document).ready(function() {});, it will initialise your audio object on DOM load, before page contents are loaded.