I want to use the youtube iframe api to manipulate the way my customer's experience videos on my site. I'm using the youtube iframe player API to initialize the player and get access to events. For the onReady event, I pass in a function that adds a thumbnail overlay over the iframe, so that means that my users' no longer have access to the native controls. On initialization of the player, I attached an event listener to the container div, which contains both the iframe and the overlay so that when it is clicked, I get the state of the video player and if a condition is met, I call player.playVideo(). Sometimes it works, sometimes it doesn't.
The pattern of the events broadcasted when a video does play properly are -1, 3, and 1.
The pattern of the events broadcasted when a video does NOT play properly are -1, 3, and -1.
Is there a possible race condition that is pausing the video while the player is buffering the video? Note, everything works find if I click the player itself.
console.log('setting up');document.addEventListener('DOMContentLoaded', function() { console.log('loaded') if (window.hideYTActvated) return; if (typeof YT === 'undefined') { let tag = document.createElement('script'); tag.src = "https://www.youtube.com/iframe_api"; let firstScriptTag = document.getElementsByTagName('script')[0]; console.log("fst: ", firstScriptTag); firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); } let onYouTubeIframeAPIReadyCallbacks = []; let style = document.createElement('style'); let newClasses = ""; let regExp = /^.*(youtu\.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/; for (let playerWrap of document.querySelectorAll(".hytPlayerWrap")) { console.log('we inside') let playerFrame = playerWrap.querySelector("iframe"); let videoURL = playerFrame.src; let matched = videoURL.match(regExp); let videoID = matched[2]; let imgUrl = `https://img.youtube.com/vi/${videoID}/hqdefault.jpg`; newClasses += `.tn-${videoID}::before {content: ""; position: absolute; top: 0; left: 0; bottom: 0; right: 0; cursor: pointer; background-size: cover; background-image: url(${imgUrl}); background-position: center; background-repeat: no-repeat;}` let onPlayerStateChange = function(event) { if (event.data == 0) { playerWrap.classList.add(`tn-${videoID}`); playerWrap.classList.add("replay-overlay"); } else if (event.data == 2) { playerWrap.classList.add(`tn-${videoID}`); playerWrap.classList.add("pause-overlay"); } else if (event.data == 1) { playerWrap.classList.remove(`tn-${videoID}`); playerWrap.classList.remove("replay-overlay"); playerWrap.classList.remove("pause-overlay"); playerWrap.classList.remove("spinner"); } else if (event.data == 3) { playerWrap.classList.remove("pause-overlay"); playerWrap.classList.add("spinner"); } else if (event.data === -1) { playerWrap.classList.remove(`tn-${videoID}`); player.playVideo(); } }; function onPlayerReady() { console.log('player is ready'); playerWrap.classList.add(`tn-${videoID}`); playerWrap.classList.add("pause-overlay"); } let player; onYouTubeIframeAPIReadyCallbacks.push(function() { console.log('ready for pushing') player = new YT.Player(playerFrame, { events: {'onStateChange': onPlayerStateChange,'onReady': onPlayerReady } }); }); playerWrap.addEventListener("click", function() { let playerState = player.getPlayerState(); if (playerState == 0) { player.seekTo(0); } else if (playerState == 2) { player.playVideo(); } else if (playerState == 5) { player.playVideo(); } else if (playerState == -1) { player.playVideo(); } }); } style.innerHTML = newClasses; document.getElementsByTagName('head')[0].appendChild(style); window.onYouTubeIframeAPIReady = function() { console.log('done') for (let callback of onYouTubeIframeAPIReadyCallbacks) { callback(); } }; window.hideYTActivate = true;})main { width: 100%; height: 100%; background-color: red; display: flex; justify-content: center; align-items: center;}@keyframes spin { 0% { transform: translate3d(-50%, -50%, 0) rotate(0deg); } 100% { transform: translate3d(-50%, -50%, 0) rotate(360deg); }}.spinner::after { animation: 1.5s linear infinite spin; animation-play-state: inherit; border: solid 5px #cfd0d1; border-bottom-color: #FFD41C; border-radius: 50%; content: ""; height: 80px; width: 80px; position: absolute; top: 50%; left: 50%; transform: translate3d(-50%, -50%, 0); will-change: transform; background: none;}.pause-overlay::after { content: ""; position: absolute; top: 0; left: 0; bottom: 0; right: 0; cursor: pointer; background-repeat: no-repeat; background-position: center; background-size: 80px 80px; background-image: url(data:image/svg+xml;utf8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEiIHdpZHRoPSIxNzA2LjY2NyIgaGVpZ2h0PSIxNzA2LjY2NyIgdmlld0JveD0iMCAwIDEyODAgMTI4MCI+PHBhdGggZD0iTTE1Ny42MzUgMi45ODRMMTI2MC45NzkgNjQwIDE1Ny42MzUgMTI3Ny4wMTZ6IiBmaWxsPSIjZmZmIi8+PC9zdmc+);}.replay-overlay::after { content: ""; position: absolute; top: 0; left: 0; bottom: 0; right: 0; cursor: pointer; background-color: transparent; background-repeat: no-repeat; background-position: center; background-size: 64px 64px; background-image: url(data:image/svg+xml;utf8;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiB2aWV3Qm94PSIwIDAgNTEwIDUxMCI+PHBhdGggZD0iTTI1NSAxMDJWMEwxMjcuNSAxMjcuNSAyNTUgMjU1VjE1M2M4NC4xNSAwIDE1MyA2OC44NSAxNTMgMTUzcy02OC44NSAxNTMtMTUzIDE1My0xNTMtNjguODUtMTUzLTE1M0g1MWMwIDExMi4yIDkxLjggMjA0IDIwNCAyMDRzMjA0LTkxLjggMjA0LTIwNC05MS44LTIwNC0yMDQtMjA0eiIgZmlsbD0iI0ZGRiIvPjwvc3ZnPg==);}.hytPlayerWrap { width: 300px; height: 200px; background-color: green;}<main><div class="hytPlayerWrap"><iframe style="width: 100%; height: 100%;" src="https://www.youtube.com/embed/jV1vkHv4zq8?rel=0&enablejsapi=1" title="YouTube video player" frameborder="0"></iframe></div></main>onStateChange event fires whenever the player's state changes and possible values are:
- -1 (unstarted)
- 0 (ended)
- 1 (playing)
- 2 (paused)
- 3 (buffering)
- 5 (video cued)