We have a website that loops through a playlist of Vimeo IDs, embedding an iFrame player until the video is done playing, destroying said I frame and starting over with the next video id. This seemingly works fine but stops working after an arbitrary number of idle hours. Our tests have been made in Chrome 59 on OSX. Here is a screenshot of the kind of errors that end up in our console.
As this is my first post, here's the link to the screenshot
We're not sure what could be causing this. Any help will be greatly appreciated!
EDIT: Here's the Javascript responsible for creating/destroying iframes. Also, the project is using AngularJS but I don't think it's relevant. :
var iframe_wrap = document.getElementById('player-wrap');
var iframe = document.getElementById('player');
var player = $f(iframe);
player.addEvent('ready', function() {
player.addEvent('finish', onFinish);
});
function onFinish() {
// Remove current iframe
iframe.parentNode.removeChild(iframe);
iframe = null;
player = null;
// Video increment
if((ctrl.currentVideo + 1) < ctrl.currentPlaylist.length) {
ctrl.currentVideo += 1;
}
else {
ctrl.currentVideo = 0;
}
// Create new iframe
var newPlayer = '<iframe id="player"
src="'+ctrl.currentPlaylist[ctrl.currentVideo].urlVimeo+'"
frameborder="0" webkitallowfullscreen mozallowfullscreen
allowfullscreen></iframe>';
if(ctrl.currentPlaylist[ctrl.currentVideo].contentType =='scenario'){
iframe_wrap.innerHTML = newPlayer;
}
iframe = document.getElementById('player');
player = $f(iframe);
player.addEvent('ready', function() {
player.addEvent('finish', onFinish);
});
$scope.$apply();
}
Related
I am a beginner JS user, and I am trying to get a video to play on fullscreen and replace an invisible div further down on the page. I started with a guide from Chris Ferdinandi.
In his guide, the video replaces the image that is clicked. I would like to have the div later down on the page to be replaced on the click.
Any guidance would be great!
HTML
<a data-video="480459339" class="stylsheetref" href="#" target="">Watch the Tour</a>
<div id="video-replace"></div>
Javascript (modified from this guide)
<script>
if (!Element.prototype.requestFullscreen) {
Element.prototype.requestFullscreen = Element.prototype.mozRequestFullscreen || Element.prototype.webkitRequestFullscreen || Element.prototype.msRequestFullscreen;
}
// Listen for clicks
document.addEventListener('click', function (event) {
//Set invisible Div (new code added by me)
var videonew = '#video-replace');
// Check if clicked element is a video link
var videoId = event.target.getAttribute('data-video');
if (!videoId) return;
// Create iframe
var iframe = document.createElement('div');
iframe.innerHTML = '<p>x</p><iframe width="560" height="960" src="https://player.vimeo.com/video/' + videoId + '?rel=0&autoplay=1" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>';
var video = iframe.childNodes[1];
// Replace the image with the video
event.target.parentNode.replaceChild(video, videonew);
// Enter fullscreen mode
video.requestFullscreen();
}, false);
</script>
There are problems in your code.
var videonew = '#video-replace'); there's an orphan ), since you are using this in the `replaceChild``method I assume you want the variable to reference to an element.
So change it to
var videonew = document.querySelector('#video-replace');
Pro tip: Using the Developer console during development can help you figure out such errors in your code.
I added the ability to display a youtube video within a Lightbox on my website. However, the code I found to help with this doesn't have a close (X) on the Lightbox. Whilst it does close by just clicking anywhere on the mask, I think not all web users are going to realise this, so I added a simple
x
onto the Lightbox div. Whilst this does actually give a functional closing (X) on the lightbox, it has the undesirable effect of the page being back at the top when the Lightbox has closed.
What I ideally want is for the Lightbox to simply close, and the page remains in the same place as it was when it opens, which is what happens if I just click on the mask.
I can see there is a section commented '// Hide lightbox when clicked on', but I have no clue how I can make an (X) also trigger this same action.
Here is the complete script used.
<div id="youtubelightbox" class="parent">x
<div class="centeredchild">
<div class="videowrapper">
<div id="playerdiv"></div>
</div>
</div>
</div>
<script>
// load Youtube API code asynchronously
var tag = document.createElement('script')
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0]
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag)
var isiOS = navigator.userAgent.match(/(iPad)|(iPhone)|(iPod)/i) != null //boolean check for iOS devices
var youtubelightbox = document.getElementById('youtubelightbox')
var player // variable to hold new YT.Player() instance
// Hide lightbox when clicked on
youtubelightbox.addEventListener('click', function(){
this.style.display = 'none'
player.stopVideo()
}, false)
// Exclude youtube iframe from above action
youtubelightbox.querySelector('.centeredchild').addEventListener('click', function(e){
e.stopPropagation()
}, false)
// define onYouTubeIframeAPIReady() function and initialize lightbox when API is ready
function onYouTubeIframeAPIReady() {
createlightbox()
}
// Extracts the Youtube video ID from a well formed Youtube URL
function getyoutubeid(link){
// Assumed Youtube URL formats
// https://www.youtube.com/watch?v=Pe0jFDPHkzo
// https://youtu.be/Pe0jFDPHkzo
// https://www.youtube.com/v/Pe0jFDPHkzo
// and more
//See http://stackoverflow.com/a/6904504/4360074
var youtubeidreg = /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/ ]{11})/i;
return youtubeidreg.exec(link)[1] // return Youtube video ID portion of link
}
// Creates a new YT.Player() instance
function createyoutubeplayer(videourl){
player = new YT.Player('playerdiv', {
videoId: videourl,
playerVars: {autoplay:1,
rel:0,
showinfo:0,
fs:0
}
})
}
// Main Youtube lightbox function
function createlightbox(){
var targetlinks = document.querySelectorAll('.lightbox')
for (var i=0; i<targetlinks.length; i++){
var link = targetlinks[i]
link._videoid = getyoutubeid(link) // store youtube video ID portion of link inside _videoid property
targetlinks[i].addEventListener('click', function(e){
youtubelightbox.style.display = 'block'
if (typeof player == 'undefined'){ // if video player hasn't been created yet
createyoutubeplayer(this._videoid)
}
else{
if (isiOS){ // iOS devices can only use the "cue" related methods
player.cueVideoById(this._videoid)
}
else{
player.loadVideoById(this._videoid)
}
}
e.preventDefault()
}, false)
}
}
if (isiOS){ // iOS devices can only use the "cue" related methods
player.cueVideoById(this._videoid)
}
else{
player.loadVideoById(this._videoid)
}
After some trial and error I figured this out.
I changed the html to
<div id="youtubelightbox" class="parent">
<div class="centeredchild"><div id="x">x</div>
<div class="videowrapper">
<div id="playerdiv"></div>
</div>
</div>
</div>
And added the following to the script
x.addEventListener('click', function(){
youtubelightbox.style.display = 'none'
player.stopVideo()
}, false)
I am running the following code which changes the source of an html5 video at the end of each video, so that it constantly plays one video after another. After the first video finishes, it runs the second, then the third and eventually starts again from the beginning, resulting in an endless cycle. It also chooses a random starting point, but that is not important for my question.
In the code below you will only find two video sources but the final code would use around ten or so.
My problem is that there is a small pause between the end of a video and the beginning of the next one. I have made the background-color of the video tag red so that you will be able to see a red flash between the playback of each video.
I'm guessing that this could be solved by preloading all videos specified inside the javascript code. So what I would like to achieve is to preload only the next video in the list specified inside the javascript code when the current video is playing. So when video nr. 5 is playing, it should preload video nr. 6 etc..
Or is this not something that could be solved by effective buffering / preloading? I'm happy about any other suggestions as well..
var vidElement = document.getElementById('video');
var vidSources = [
"http://www.w3schools.com/html/mov_bbb.mp4",
"http://www.w3schools.com/html/movie.mp4"
];
var activeVideo = Math.floor((Math.random() * vidSources.length));
vidElement.src = vidSources[activeVideo];
vidElement.addEventListener('ended', function(e) {
// update the active video index
activeVideo = (++activeVideo) % vidSources.length;
if(activeVideo === vidSources.length){
activeVideo = 0;
}
// update the video source and play
vidElement.src = vidSources[activeVideo];
vidElement.play();
});
video { background-color: red }
<video src="http://www.w3schools.com/html/mov_bbb.mp4" id="video" autoplay muted playsinline></video>
<p>(each video is just ~ 10 seconds)</p>
You can create video elements with preload attribute and add it to div containar like follows:
function initVideoElement(videoEl)
{
videoEl.playsinline = true;
videoEl.muted = false;
videoEl.preload = 'auto'; //but do not set autoplay, because it deletes preload
//loadedmetadata is wrong because if we use it then we get endless loop
videoEl.onplaying = function(e)
{
if(++nextActiveVideo == 2)
nextActiveVideo = 0;
//replace the video elements against each other:
if(this.inx == 0)
nextVideoElement = videoElements[1];
else
nextVideoElement = videoElements[0];
nextVideoElement.src = vidSources[nextActiveVideo];
nextVideoElement.pause();
};
videoEl.onended = function(e)
{
this.style.display = 'none';
nextVideoElement.style.display = 'block';
nextVideoElement.play();
};
}
var videoContainer = document.getElementById('videoContainer'),
nextActiveVideo = 0,
nextVideoElement,
videoElements =
[
document.createElement('video'),
document.createElement('video')
],
vidSources =
[
"http://www.w3schools.com/html/mov_bbb.mp4",
"http://www.w3schools.com/html/movie.mp4"
];
videoElements[0].inx = 0; //set index
videoElements[1].inx = 1;
initVideoElement(videoElements[0]);
initVideoElement(videoElements[1]);
videoElements[0].autoplay = true;
videoElements[0].src = vidSources[0];
videoContainer.appendChild(videoElements[0]);
videoElements[1].style.display = 'none';
videoContainer.appendChild(videoElements[1]);
video{background-color: red}
<div id="videoContainer"></div>
I am using easytabs.js to display some content. On one of the tabs is a youtube video with a custom image. The youtube video plays when the custom image is clicked. However I would like the youtube video to pause when one of the other tabs are clicked.
The test page is here: http://toddyhotpants.com/test/
If anyone has any ideas I would love to hear them!
Thanks!
The YouTube video player has a JavaScript APi you can use to work with videos loaded on your page.
You can find the docs here: https://developers.google.com/youtube/js_api_reference
As you can see there, add this to the video URL when you load it: &enablejsapi
Then when it is loaded it will call the onYoutubePlayerReady call back after which player will be available for you to call player.playVideo() and player.pauseVideo().
Let me know how it goes.
UPDATE:
Here is the example, this should pause a video after a tab is switched with easytabs.
I got the easytabs code from their site and it has jQuery so I assume that is a requirement and you already have it.
Remember to change the container ID for your tab div in the code, and set any easytab options you need to set.
<script type="text/javascript">
var yPlayer = false;
function onYouTubePlayerReady(playerId) {
yPlayer = document.getElementById(playerId);
}
$('#YOUR-TAB-CONTAINER-ID-HERE')
.easytabs({
//put your options here
})
.bind('easytabs:after', function(e, tab){
if ( ! tab.hasClass('active') && ! tab.hasClass('collapsed') ) {
yPlayer.pauseVideo();
}
});
</script>
UPDATE 2:
Based on your comment I've come up with this:
<script>
$(function(){
var player = false;
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubePlayerAPIReady() {
player = new YT.Player('ytplayer', {
height: '670',
width: '470',
videoId: 'nsjPrsmsll0 '
});
$('#YOUR-TAB-CONTAINER-ID-HERE')
.easytabs({
//put your options here
})
.bind('easytabs:after', function(e, tab){
if ( ! tab.hasClass('active') && ! tab.hasClass('collapsed') ) {
player.pauseVideo();
}
});
}
});
</script>
Replace your youtube video iframe with the this: and use the JS code I provided.
Following is Function to embed youtube video in html.
In this youtube video display on click but I want to do this on load using javascript.
How can be done? Any help?
youtubeLoadVideos : function () {
// Find all the YouTube video embedded on a page
var videos = document.getElementsByClassName("youtube");
for (var i=0; i<videos.length; i++) {
var youtube = videos[i];
// Attach an onclick event to the YouTube Thumbnail
youtube.onclick = function() {
// Create an iFrame with autoplay set to true
var iframe = document.createElement("iframe");
iframe.setAttribute("src", "https://www.youtube.com/embed/" + this.id);
// The height and width of the iFrame should be the same as parent
iframe.style.width = this.style.width;
iframe.style.height = this.style.height;
iframe.style.clear = 'both';
// Replace the YouTube thumbnail with YouTube HTML5 Player
this.parentNode.replaceChild(iframe, this);
};
}
}
As you create it onload, just create a html tag:
<iframe src="https://www.youtube.com/embed/yourid"/>
Or use javascript, as there is only 1 should be loaded as default:
window.onload = function(){
var videos = document.getElementsByClassName("youtube");
if (videos.length > 0){
var youtube = videos[0];
var iframe = document.createElement("iframe");
iframe.setAttribute("src", "https://www.youtube.com/embed/" + youtube.id);
// The height and width of the iFrame should be the same as parent
iframe.style.width = youtube.style.width;
iframe.style.height = youtube.style.height;
iframe.style.clear = 'both';
// Replace the YouTube thumbnail with YouTube HTML5 Player
youtube.parentNode.replaceChild(iframe, youtube);
}
}
Another case, if you need to keep the onclick and load 1 video by default, just keep your code and write some more lines:
window.onload = function(){
var videos = document.getElementsByClassName("youtube");
if (videos.length > 0){
var youtube = videos[0]; //play the first video onload
youtube.click(); //trigger click programmatically, this will cause the event handler to be executed and insert an iframe.
}
}