I've made a live-feed for my website. Every 30 seconds the content reloads. But now I have a problem. When I'm adding an embedded video (from Youtube) or an HTML5 <video>, I can't play the video completely because of the reload. Is it possible to stop the auto reload when the video is playing, and restart the reload when the video has stopped?
This is what I use for the reload:
$(document).ready(function() {
$("#updates").load("updates.php");
var refreshId = setInterval(function() {
$("#updates").load('updates.php' + '?randval=' + Math.random());
}, 30000);
$.ajaxSetup({
cache: false
});
});
You can video my live-feed here.
The following is untested. One thing beforehand - you can't handle an html5 video element the same way like an embedded youtube iframe.
In case you have a video element you can interact directly with it and use the eventhandlers for play, pause and end to handle your request. A possible solution could look something like this:
$(function() {
var refreshId;
// collection of all video elements on your page
var videos = $('video');
// disable reload by clearing the interval
function blockReload() {
clearInterval(refreshId);
}
// your existing reload function
function startReload() {
refreshId = setInterval(function() {
$("#updates").load('updates.php' + '?randval=' + Math.random());
}, 30000);
}
// loop over all video elements on your page and bind
// three event handlers, one for playing, one for pausing
// and one for an ended video.
videos.each(function() {
this.addEventListener('playing', blockReload);
this.addEventListener('paused', startReload);
this.addEventListener('ended', startReload);
});
});
Since you can't control embedded elements directly, you'll need to work with the youtube API.
Instead of using the iframe from youtube, you use the API to load the video like this (example from the API page):
// This code loads the IFrame Player API code asynchronously.
// you could also use a normal script tag in that case you would load
// the lib each time.
var tag = document.createElement('script');
tag.src = "http://www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
Next you load the video via the script library:
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '360'
width: '640',
videoId: 'YOURVIDEOID',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
Now you can interact with the youtube video:
function onPlayerStateChange(event) {
// check if video is running...
if (event.data == YT.PlayerState.PLAYING) {
// disable interval
blockReload();
} else {
// restart interval
startReload();
}
}
I found this solution by trial and error (I used axel.michel's functions Blockreload() and StartReload()).
You can add onplay="" and onended="" to the video-tag (it also works for the audio-tag). onplay="" loads the function Blockreload(), onended="" loads the function StartReload().
It looks like this:
<video id="test" onplay="BlockReload()" onended="StartReload()" width="800" controls>
<source src="*video source*">
Jouw browser ondersteund onze videoplayer niet.
</video>
Related
I am new to CS and currently working on personal projects. I am creating a web app where a user can copy and paste a YouTube URL to a video in a search box and then have the ability to watch the video on the same web page after clicking watch. To get the video ID, I have used a regex:
function getId(url) {
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
const match = url.match(regExp);
return (match && match[2].length === 11)
? match[2]
: null;
}
And this is how I am getting the user input:
var inputVal = document.getElementById("userInput").value;
To get the video ID, I am calling getId on the inputVal from the user:
var newVideoId = getId(inputVal)
Below is the YouTube API used to play a video on my page. However, I am finding it difficult to passing in the newVideoId variable to the API under the player object.
// 2. This code loads the IFrame Player 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);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'newVideoId', //the problem lies here
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
}
The problem is that, nothing shows on my screen after clicking the button. I am able to console.log the ID; that means I am getting the correct ID from the regex equation.
I would appreciate any help on how to use a dynamic ID gotten from user in the API! Thanks
To play a video with the iframe api providing a video Id you can use this function:
loadVideoById({'videoId': 'bHQqvYy5KYo',
'startSeconds': 5,
'endSeconds': 60,
'suggestedQuality': 'large'});
From IFrame Player API:
This function loads and plays the specified video.
The required videoId parameter specifies the YouTube Video ID of the
video to be played. In the YouTube Data API, a video resource's id
property specifies the ID. The optional startSeconds parameter accepts
a float/integer. If it is specified, then the video will start from
the closest keyframe to the specified time. The optional endSeconds
parameter accepts a float/integer. If it is specified, then the video
will stop playing at the specified time.
This should do the trick.
To my problem, I have one link . I want to play the video by clicking the link in a fancybox overlay window. This is not a problem. The problem is the parameters, for example "autoplay" or "autohide".
The following link doesn't work:
The Overlay-Window opened, but the video is not playing automatically.
EDIT: I want to use the HTML5 Player on mobile devices. On a desktop-browser it works with the parameters, but not on mobile devices.
As it turns out, autoplay cannot be done on iOS devices (iPhone, iPad, iPod touch) and Android.
See https://stackoverflow.com/a/8142187/2054512 and https://stackoverflow.com/a/3056220/2054512
Have a look on code below.
Tested and found working on Mobile and Tablet devices.
<!-- 1. The <iframe> (video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player 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);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
The code below was tested on iPhone, iPad (iOS13), Safari (Catalina). It was able to autoplay the YouTube video on all devices. Make sure the video is muted and the playsinline parameter is on. Those are the magic parameters that make it work.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=2.0, minimum-scale=1.0, user-scalable=yes">
</head>
<body>
<!-- 1. The <iframe> (video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player 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);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
width: '100%',
videoId: 'osz5tVY97dQ',
playerVars: { 'autoplay': 1, 'playsinline': 1 },
events: {
'onReady': onPlayerReady
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.mute();
event.target.playVideo();
}
</script>
</body>
</html>
The official statement "Due to this restriction, functions and parameters such as autoplay, playVideo(), loadVideoById() won't work in all mobile environments.
Reference: https://developers.google.com/youtube/iframe_api_reference
There is a way to make youtube autoplay, and complete playlists play through. Get Adblock browser for Android, and then go to the youtube website, and and configure it for the desktop version of the page, close Adblock browser out, and then reopen, and you will have the desktop version, where autoplay will work.
Using the desktop version will also mean that AdBlock will work. The mobile version invokes the standalone YouTube player, which is why you want the desktop version of the page, so that autoplay will work, and so ad blocking will work.
How to use a Youtube channel live url to embed and autoplay. Instead of Video ID that has to be constantly updated for live stream changes.
I mixed two sets of code and came up with a working auto play Youtube video embed from a channel live stream.
My thanks to both of the other contributors for their help. Hopefully this helps someone else some time.
Example stream
https://www.youtube.com/embed/live_stream?channel=UCwobzUc3z-0PrFpoRxNszXQ
The code below by Zubi answered Nov 25 '16 at 7:20 works with Youtube videos.
With code by Darien Chaffart found at
https://stackoverflow.com/a/61126012/1804252
Example
<html>
<head>
</head>
<body>
<center>
<script src="https://www.youtube.com/iframe_api"></script>
<!-- Insert Livestream Video -->
<iframe id="live-video" src="https://www.youtube.com/embed/live_stream?channel=UCwobzUc3z-0PrFpoRxNszXQ&enablejsapi=1" width="100%" height="100%" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen enablejsapi="1"></iframe>
<!-- Basic API code for Youtube videos -->
<script>
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('live-video', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady() {
var url = player.getVideoUrl(); /*Use Youtube API to pull Video URL*/
var match = url.match(/[?&]v=([^&]+)/);
var videoId = match[1]; /*Use regex to determine exact Video URL*/
// Insert a new iFrame for the livestream chat after a specific div named chatframe*/
var livevid = document.createElement("iframe");
livevid.src = 'https://www.youtube.com/live_chat?v=' + videoId + ''
livevid.width = '100%';
livevid.height= '100%';
document.getElementById("chatframe").appendChild(livevid);
}
function onPlayerStateChange() {
}
function onPlayerReady(event) {
event.target.playVideo();
}
// The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 90000000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
</script>
</center>
</body>
</html>
So I've got a small app with two panels. Using the iframe API. Clicking on one panel will expand the panel full screen, as well as showing a 'play video' button with some additional information. Clicking a button in the top left will return the UI to it's standard state, closing down the video and shrinking the panels back to fit 50/50.
Now as we've got two videos, I've defined the videos as such, #vidPlayer2 being the second trigger.
$('#vidPlayer1').on('click', function(){
player = new YT.Player('player', {
height: '100%',
width: '100%',
videoId: '(video id here)',
controls: 0,
showinfo: 0,
autoplay: 0,
rel: 0,
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
Similarly, we've got the default demo code, with a small modification:
function onPlayerReady(event) {
event.target.playVideo();
}
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
done = true;
}
if (event.data == YT.PlayerState.ENDED) {
resetView();
}
}
function stopVideo() {
player.stopVideo();
}
Then, we're trying to get the button to work. In some circumstances, not having clicked one of the vidPlayer buttons, no player is defined, so I threw in an if statement with some validation.
var resetView = function() {
// If a Youtube player is active, make sure we stop it.
if (player === undefined || !player || null) {
console.log("Player could not be found.");
} else {
player.stopVideo();
player.destroy();
}
// Additional code to reset the UI removed below. Works no matter what if the above code is removed.
};
Now for the most part, things work well UNTIL I try to go into a panel, play a video, reset UI, then try to enter and leave the next panel without playing a video. When I follow this exact series of steps, regardless of what panel starts first, I get a TypeError: this.a is null in console. I would've assumed that the validation would've done the trick, but apparently not.
So what I can distinguish from this is it works fine when initialized - i.e. var player is initialized. The return button works through just going back and forth without playing a video. The return button works when a video is actively playing, but the function fails if we try to use the return directly after the player is stopped and destroyed. It does work if we simply pop open another video, however.
Is there something I'm missing when I'm trying to reset the view? Does the youtube player have to be reinitialized? Any help or thoughts would be greatly appreciated. Thanks!
Edit: This is the note that's being thrown by the console. Something to note is main.js:44:5 is the player.stopVideo(); call, and main.js:70:3 is when resetView(); is called on a button click.
TypeError: this.a is null
www-widgetapi.js:120:73
f.C
https://s.ytimg.com/yts/jsbin/www-widgetapi-vflWgX7t4/www-widgetapi.js:120:73
V
https://s.ytimg.com/yts/jsbin/www-widgetapi-vflWgX7t4/www-widgetapi.js:112:97
Nb/</this[a]
https://s.ytimg.com/yts/jsbin/www-widgetapi-vflWgX7t4/www-widgetapi.js:130:124
resetView
file:///Users/cipher/Desktop/ERHS_video/js/main.js:44:5
<anonymous>
file:///Users/cipher/Desktop/ERHS_video/js/main.js:70:3
dispatch
file:///Users/cipher/Desktop/ERHS_video/js/jquery-3.2.1.min.js:3:10264
add/q.handle
file:///Users/cipher/Desktop/ERHS_video/js/jquery-3.2.1.min.js:3:8326
The problem here is player is NOT undefined. What's happening is you have a global player reference, and you're doing the following with it:
Creating a player in the first panel
Destroying it when the first panel closes
Calling player.stopVideo() on the already destroyed player (from the first panel) when the second panel closes
Currently, player holds a reference to whatever the last YouTube player you were using is, even if that player has already been destroyed.
What you should be doing is clearing out your reference to the player when you destroy it. Destroy won't (and can't) do that. You can also simplify your if condition since !player will check for null and undefined on its own:
var resetView = function() {
// If a Youtube player is active, make sure we stop it.
if (!player) {
console.log("Player could not be found.");
} else {
player.stopVideo();
player.destroy();
player = null; // Clear out the reference to the destroyed player
}
Highly inspired from IkeDoud's above answer and some others like this one, one year later, here is my way to avoid other video suggestions on play end in embedded API player:
<div id="player"></div>
<style>
#player{
min-width:auto;
min-height:auto;
}
</style>
<script>
// Load the IFrame Player 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);
// Initialise the player with options
var player;
var playerOptions = {
videoId: 'ViDeOiD_HeRe',
events: {
'onStateChange': onPlayerStateChange
}
};
// Load the video whern player ready
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', playerOptions);
}
// On video end, reset the player back to poster image
function onPlayerStateChange(event) {
if(event.data === 0) {
$(PaReNt_sElEcToR).find("#player").replaceWith('<div id="player"></div>');
player = null;
player = new YT.Player('player', playerOptions);
}
}
</script>
No more irrelevant suggestions playable from the embedded video container.
And no autoplay (mobile forbids it anyway) to have the poster (thumbnail) image.
On event.data === 0, which is video end... Destroy and reload the Iframe.
I am dealing with this code written by somebody else and it is to load an image and a YouTube Video. My understanding his that I can change the priority of the script. Right now, it seems that when someone goes on this website with an iPhone and they hit the play button in front of the image, the video does not play, because the script is not finished loading. How do I alter the code below so that if the page or this script is not finished loading, the end user cannot see a play button?
By the way, this problem does not happen on an Android device, so I am not sure if that piece of information will serve as a clue.
I hope this makes sense because I am still trying to wrap my head around it.
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
var player1;
var player2;
function onYouTubeIframeAPIReady() {
player1 = new YT.Player('player', {
height: '390',
width: '640',
playerVars: {
'controls': 0,
'rel': 0
},
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
jQuery('.video-overlay').click(function() {
event.target.setVolume(100);
event.target.setPlaybackQuality('hd1080');
setTimeout(function() {
jQuery('.video-overlay').css('transform', 'scale(0)');
jQuery('.homepage-tagline').hide();
}, 300);
event.target.playVideo();
});
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
jQuery('.video-overlay').click(function() {
event.target.setPlaybackQuality('hd1080');
jQuery('.video-overlay').hide();
jQuery('.slider-overlay').hide();
event.target.playVideo();
});
}
function stopVideo() {
player.stopVideo();
}
I tried adding this piece of code:
jQuery('.video-overlay').css('opacity', 0);
but it didn't do much.
It would be best to set the pointer-events to none and when onPlayerReady is fired, set the target.style.pointerEvents = "all"
I am trying to get a "pause" event with the YouTube API on a YouTube video created by AMP (Accelerated Mobile Pages) with this basic example: https://ampbyexample.com/components/amp-youtube/
The code works and I get a video showing. The next thing I wanted to do was do something when the video is paused. I've had a look on how to do this and I've got the current code:
//The iframe generated from AMP does not give an ID so I have added one
$('#AMP_1 iframe').attr('id', 'yt_player');
//Load API code
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 player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('yt_player', {
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady() {
console.log("READY");
}
function onPlayerStateChange() {
console.log("STATE CHANGE");
}
When I run this I am not getting console errors and none of the console.log calls are displaying anything. The player variable stays undefined.
The iframe produced by AMP does have "enablejsapi=1" in the URL.
Do I need to do anything/am I missing something, to get the pause event on the video?
You need to have a parameter on function onPlayerStateChange to get the event data.
function onPlayerStateChange(event) {
switch(event.data){
case 2:
console.log("PAUSE!")
break;
}
}
other event.data list
-1 (unstarted)
0 (ended)
1 (playing)
2 (paused)
3 (buffering)
5 (video cued).