Youtube Javascript API pause and Play Function - javascript

I've been struggling with this for some days now. I use the function below to control a youtube video embedded with an iframe. The initialize function works properly. The problem is the onPlayerStateChange function. I'm trying to control the pause and play using the same button but it doesn't seem to run properly. It doesn't pause the video and the video itself cracks(plays at a very slow rate).
var player, time_update_interval = 0;
function onYouTubeIframeAPIReady() {
player = new YT.Player('videod', {
playerVars: {
color: 'white'
},
events: {
'onReady': doThisFirst,
'onStateChange': onPlayerStateChange
}
});
}
function doThisFirst(){
updateTimerDisplay();
clearInterval(time_update_interval);
time_update_interval = setInterval(function () {
updateTimerDisplay();
}, 1000);
$('#volume-input').val(Math.round(player.getVolume()));
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING) { // If video is playing…
var stop = document.getElementsByClassName('playButton');
stop[0].click(player.pauseVideo());
}
else{ // If video – pause
var start = document.getElementsByClassName('playButton');
start[0].click(player.playVideo());
}
}

Related

How to fix getPlayerState for Youtube API to return int value?

ERROR:
selenium.common.exceptions.JavascriptException: Message: javascript error: Cannot read property 'getPlayerState' of null
or
Message: javascript error: getPlayerState is not a function
HTML Code:
<div id="movie_player"></div>
Javascript Code:
<script src="http://www.youtube.com/player_api"></script>
<script>
// create youtube player
var player;
var video_id = 'qCTMq7xvdXU';
let player_vars = {"playsinline": 1, "origin": "https://www.youtube.com"}
function onYouTubeIframeAPIReady() {
player = new YT.Player('movie_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();
}
function cueVideo(url) {
player.cueVideoByUrl(url);
}
function VideoReady(id) {
player.loadVideoById(id);
}
Python Code:
self.driver.execute_script(
"ytplayer = document.getElementById('player');")
player_status = self.driver.execute_script(
"return ytplayer.getPlayerState();")
print(player_status)
Ideally, I want getPlayerState() to return the player's status as -1, 0, 1, 2, 3, 4, 5 which will allow me to proceed with the next steps. If the status code is 0(or finished), then load the next song using selenium.execute_script with the videoId loaded from the Python script.
Edit: Typing console.log(player.getPlayerState()) prints out the actual value for the player. So getPlayerState() IS A FUNCTION.

YT.Player doesn't return an instance with playVideo()

When I create an instance of YT.Player(HTMLIFrameElement, { options }) I get back an object that has:
destroy
setSize
getIframe
addEventListener
getVideoEmbedCode
getOptions
getOption
But not playVideo, pauseVideo etc as described in the documentation.
I got a demo here: http://siesta-annotations.surge.sh/Siesta_webviewer_test/?page=3
I am creating the iframes via the DOM in trait.playable.youtube.js and adding the iframe to a documentFragment that eventually will be added to a div:
const element = document.createElement('iframe')
element.src = `https://www.youtube.com/embed/${id}?rel=0;&autoplay=${this.options.autostart ? 1 : 0};&enablejsapi=1;&origin=${location.hostname};`
element.style = this.inlineStyle
I then create an instance of YT.Player:
// nasty initialization because we're outside webpack and this is a demo
if (global.YT.loaded) {
this.player = new global.YT.Player(element, {
events: {
'onStateChange': this.stateHandler,
'onReady': onPlayerReady
}
})
} else {
const oldHandler = global.onYouTubeIframeAPIReady
global.onYouTubeIframeAPIReady = () => {
if (oldHandler) oldHandler()
this.player = new global.YT.Player(element, {
events: {
'onStateChange': this.stateHandler,
'onReady': onPlayerReady
}
})
}
}
The instance of YT.Player looks something like this:
It looks like the minification process went very wrong. What am I doing wrong - how should I initialise YT.Player for my use-case?
This is my second post, I hope that I can solve your problem.
I am not 100% sure about how your code works, but I suspect ...
It seems like a double instantiation of the YT.Player object, which will cause the YT.Player object unstable.
I myself also struggled for a long time (ps: I am an amateur programmer.😅)
As an example, the following snippets is modifed from Youtube Iframe API website and an example of how the second instantiation will break the player object try it! JS Bin:
<!DOCTYPE html>
<html>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
</br>
<button onclick="instantiateOneMore()">
Call
<pre>new YT.Player('player')</pre>
</button>
<button onclick="pauseVideo()">
pauseVideo();
</button>
<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
}
});
}
let callTime = 0;
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
callTime ++;
console.log(callTime);
//document.querySelector('#dd').innerHTML = player.pauseVideo;
}
function pauseVideo(){
player.pauseVideo();
}
instantiateOneMore = () => {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
//document.querySelector('#dd').innerHTML = player.pauseVideo;
}
// 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>
</body>
</html>
Furthermore, the second onPlayerReady(), won't even be called. So if you intend to put some counter to see how many times the new YT.Player(...) is called, you will suspect it only be called once. Which makes the effect ghost away from debugging.
Strangely enough you do not get access to the YTPlayer API until 'onReady' is called in the constructor player options object. https://developers.google.com/youtube/iframe_api_reference#Loading_a_Video_Player
function onYouTubeIframeAPIReady() {
new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': function (event) {
onPlayerReady(event.target)
},
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerReady(player) {
player.playVideo();
}
This of course only works for one player, so you need to roll out your own YouTube player manager if you want to handle multiple players. (I know the API is insane)
A quick solution could be the following if you have iframes with youtube videos (untested):
const YTManager = {
videos: [],
youtubeApiReady = false,
initialize () {
const matchId = /[^/]+$/
this.youtubeApiReady = true
document.querySelectorAll('iframe[src*="youtube"]')
.forEach(iframe => this.videos.push({
dom: iframe,
player: null,
videoId: iframe.src.exec(matchId) || iframe.src.exec(matchId)[0]
}))
},
createPlayers () {
if (this.youtubeApiReady === false) return
this.videos.forEach(v => {
new YT.Player(v.dom.id, {
videoId: v.videoId,
events: {
'onReady': function (event) {
v.player = event.target
}
}
})
})
},
find (id) {
return this.videos.find(v => v.id === id)
},
play (id) {
const video = this.find(id)
if (this.youtubeApiReady && video && video.player) {
video.playVideo()
}
},
pause (id) {
const video = this.find(id)
if (this.youtubeApiReady && video && video.player) {
video.pauseVideo()
}
},
}
window.onYouTubeIframeAPIReady = function onYouTubeIframeAPIReady() {
// YouTube client side script has been loaded
YTManager.youtubeApiReady = true
YTManager.createPlayers()
}
document.addEventListener("DOMContentLoaded", function() {
// all iframes has been parsed by the browser
YTManager.initialize()
});
Of course you can not call YTManager.play or YTManager.pause without having the ID and wait for the YouTube script to load and then the video initialization to finish. All in all, a real mess. I'm sure you can come up with a better manager. I have written one at work that is better but also works with completely different objects and requirements, so it's not a good fit for general purpose YouTube video manager. But the one above is the gist of my current player.
I recommend using iframes from the beginning - if anything goes wrong in your script, the videos will still be playable, you will just not have any control of them.
Iframed youtube videos looks like this:
<iframe
id="uniqueDOMElementID1"
width="560"
height="315"
src="https://www.youtube.com/embed/bHQqvYy5KYo"
frameborder="0"
allow="autoplay; encrypted-media"
allowfullscreen></iframe>

Rails & Youtube API: Issues loading iframe

I'm trying to implement the Youtube Iframe API into my Rails app. I'm trying to replicate the exact example on the Youtube Iframe API instructions page.
Created a yt_player.js file:
$(function() {
alert('this gets called')
// 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() {
alert('this does not get called')
player = new YT.Player('player-wrapper', {
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();
}
});
And my view:
<div id="player-wrapper"></div>
I was expecting this to work but no video is being loaded. No errors showing in console.
What am I doing wrong?
First of all, I'm pretty sure your window.player and window.onYouTubeIframeAPIReady are undefined when you check in the browser console.
The reason is the way youtube iframe api work, those above variables must be defined globally.
Let check this document
They say:
The onYouTubeIframeAPIReady function will execute as soon as the player API code downloads. This portion of the code defines a global variable, player, which refers to the video player you are embedding, and the function then constructs the video player object.
So the changes will be: (define youtube variables and callbacks globally)
// Your current code
window.player = null; // <-- change here
window.onYouTubeIframeAPIReady = function() { // <-- change here
alert('this does not get called')
player = new YT.Player('player-wrapper', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
window.onPlayerReady = function(event) { // <-- change here
event.target.playVideo();
}
window.done = false; // <-- change here
window.onPlayerStateChange = function(event) { // <-- change here
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
window.stopVideo = function() { // <-- change here
player.stopVideo();
}

Prevent subsequent autoplay in youtube javascript API

I load and play a youtube video in a fancybox. It all works perfectly, except when I close the fancybox it starts the video again.
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '480',
width: '853',
videoId: 'I76i-TCaUCY',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// autoplay video
function onPlayerReady(event) {
event.target.playVideo();
}
// when video ends
function onPlayerStateChange(event) {
if (event.data === 0) {
$.fancybox.close();
}
}
The user should be able to play it again if needed, so I can't delete it.
How do I play it for the first time only?
I don't know if there is an easier way, but this is how I have fixed it for my needs:
I added var played = false and:
// autoplay video
function onPlayerReady(event) {
//This ensures that it is autoplayed only once.
if (!played) {
event.target.playVideo();
played = true;
}
}
It now works as I was expecting.

Multiple Instances of YouTube Player API on a Single Page

I've spent the day banging my head on this. I've made some good progress, but this last part has me stuck.
I'm using YouTube's API. I have a listener event configured, and the video autoplays, and autocloses on completion. All of that works great.
What I want to do is have more than one video on a single page (5, actually) assigned by DIV. Is there a way to do that with this code?
// create youtube player
var player;
function onYouTubePlayerAPIReady() {
player = new YT.Player('player', {
height: '488',
width: '800',
videoId: '49QKXdRTX-A',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// autoplay video
function onPlayerReady(event) {
event.target.playVideo();
}
// when video ends
function onPlayerStateChange(event) {
if(event.data === 0) {
$("#player").hide();
}
}
Additionally, it's worth mentioning that I will have a couple of these videos auto-show another DIV on completion, so something like this:
function onPlayerStateChange(event) {
if(event.data === 0) {
$("#player").hide();
$("#gallery-main").show();
ANY help would be greatly appreciated. Thanks!

Categories

Resources